node-red-contrib-knx-ultimate 2.2.2 → 2.2.4
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 +6 -0
- package/nodes/hue-config.js +79 -78
- package/nodes/knxUltimate-config.js +6 -4
- package/nodes/knxUltimateHueBattery.js +69 -68
- package/nodes/knxUltimateHueButton.js +1 -1
- package/nodes/knxUltimateHueLight.html +25 -5
- package/nodes/knxUltimateHueLight.js +168 -138
- package/nodes/knxUltimateHueLightSensor.js +53 -62
- package/nodes/knxUltimateHueMotion.js +4 -4
- package/nodes/knxUltimateHueScene.js +1 -1
- package/nodes/knxUltimateHueTapDial.js +1 -1
- package/nodes/knxUltimateHueTemperatureSensor.js +70 -71
- package/nodes/utils/hueEngine.js +57 -42
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,12 @@
|
|
|
6
6
|
|
|
7
7
|
# CHANGELOG
|
|
8
8
|
|
|
9
|
+
<b>Version 2.2.4</b> - October 2023<br/>
|
|
10
|
+
- HUE Light: fixed some status hiccups and better handling of async hue bridge functions.<br/>
|
|
11
|
+
</p>
|
|
12
|
+
<b>Version 2.2.3</b> - October 2023<br/>
|
|
13
|
+
- HUE Light: Again, rewrite of the DIM function to get rid of the dimming_delta.<br/>
|
|
14
|
+
</p>
|
|
9
15
|
<p>
|
|
10
16
|
<b>Version 2.2.2</b> - October 2023<br/>
|
|
11
17
|
- NEW: HUE Motion: support HUE Camera motion events via the HUE Motion node.<br/>
|
package/nodes/hue-config.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
/* eslint-disable no-lonely-if */
|
|
2
|
+
/* eslint-disable no-param-reassign */
|
|
1
3
|
/* eslint-disable no-inner-declarations */
|
|
2
4
|
/* eslint-disable max-len */
|
|
3
5
|
const dptlib = require("../KNXEngine/src/dptlib");
|
|
@@ -5,6 +7,12 @@ const HueClass = require("./utils/hueEngine").classHUE;
|
|
|
5
7
|
const loggerEngine = require("./utils/sysLogger");
|
|
6
8
|
const hueColorConverter = require("./utils/hueColorConverter");
|
|
7
9
|
|
|
10
|
+
function getRandomIntInclusive(min, max) {
|
|
11
|
+
min = Math.ceil(min);
|
|
12
|
+
max = Math.floor(max);
|
|
13
|
+
return Math.floor(Math.random() * (max - min + 1) + min); // The maximum is inclusive and the minimum is inclusive
|
|
14
|
+
}
|
|
15
|
+
|
|
8
16
|
// Helpers
|
|
9
17
|
const sortBy = (field) => (a, b) => {
|
|
10
18
|
if (a[field] > b[field]) {
|
|
@@ -47,6 +55,7 @@ module.exports = (RED) => {
|
|
|
47
55
|
const node = this;
|
|
48
56
|
node.host = config.host;
|
|
49
57
|
node.nodeClients = []; // Stores the registered clients
|
|
58
|
+
node.nodeClientsAwaitingInit = []; // Stores the nodes client to be initialized
|
|
50
59
|
node.loglevel = config.loglevel !== undefined ? config.loglevel : "error"; // 18/02/2020 Loglevel default error
|
|
51
60
|
node.sysLogger = null;
|
|
52
61
|
node.hueAllResources = null;
|
|
@@ -85,67 +94,51 @@ module.exports = (RED) => {
|
|
|
85
94
|
(async () => {
|
|
86
95
|
try {
|
|
87
96
|
await node.loadResourcesFromHUEBridge(); // Then, you can use node.getResources, that works locally and doesn't query the HUE Bridge.
|
|
88
|
-
} catch (error) {
|
|
97
|
+
} catch (error) {
|
|
98
|
+
/* empty */
|
|
99
|
+
}
|
|
89
100
|
})();
|
|
90
101
|
if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.info("node.hueManager connected event");
|
|
91
102
|
});
|
|
92
103
|
};
|
|
93
104
|
|
|
94
105
|
// Query the HUE Bridge to return the resources
|
|
95
|
-
node.loadResourcesFromHUEBridge = (
|
|
106
|
+
node.loadResourcesFromHUEBridge = () => {
|
|
96
107
|
(async () => {
|
|
97
108
|
// °°°°°° Load ALL resources
|
|
98
109
|
try {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
node.
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
nodeClient.currentHUEDevice = oHUEDevice;
|
|
108
|
-
for (const [key, value] of Object.entries(oHUEDevice)) {
|
|
109
|
-
// Update KNX State
|
|
110
|
-
const oProperty = { id: oHUEDevice.id };
|
|
111
|
-
oProperty[key] = value;
|
|
112
|
-
nodeClient.handleSendHUE(oProperty);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
}
|
|
110
|
+
node.hueAllResources = await node.hueManager.hueApiV2.get("/resource");
|
|
111
|
+
node.hueAllRooms = node.hueAllResources.filter((a) => a.type === "room");
|
|
112
|
+
// Update all KNX State of the nodes with the new hue device values
|
|
113
|
+
if (node.nodeClientsAwaitingInit !== undefined) {
|
|
114
|
+
// Because the whole process is async, if the function await node.hueManager.hueApiV2.get("/resource") has not jet been called or is late,
|
|
115
|
+
// the node/nodes belonging to this server, has been previously added to the nodeClientsAwaitingInit list.
|
|
116
|
+
node.nodeClientsAwaitingInit.forEach((nodeClient) => {
|
|
117
|
+
node.nodeClients.push(nodeClient);
|
|
116
118
|
});
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
const oHUEDevice =
|
|
119
|
+
node.nodeClientsAwaitingInit = [];
|
|
120
|
+
}
|
|
121
|
+
node.nodeClients.forEach((nodeClient) => {
|
|
122
|
+
if (nodeClient.hueDevice !== undefined) {
|
|
123
|
+
const oHUEDevice = node.hueAllResources.filter((a) => a.id === nodeClient.hueDevice)[0];
|
|
122
124
|
if (oHUEDevice !== undefined) {
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
// Update KNX State
|
|
126
|
-
const oProperty = { id: oHUEDevice.id };
|
|
127
|
-
oProperty[key] = value;
|
|
128
|
-
_callerNode.handleSendHUE(oProperty);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
} catch (error) {
|
|
132
|
-
if (this.sysLogger !== undefined && this.sysLogger !== null) {
|
|
133
|
-
this.sysLogger.error(`KNXUltimatehueEngine: loadResourcesFromHUEBridge, from a single node that has been edited: ${error.message}`);
|
|
134
|
-
reject(error.message);
|
|
125
|
+
nodeClient.currentHUEDevice = oHUEDevice;
|
|
126
|
+
nodeClient.handleSendHUE(oHUEDevice);
|
|
135
127
|
}
|
|
136
128
|
}
|
|
137
|
-
}
|
|
138
|
-
resolve(true);
|
|
129
|
+
});
|
|
139
130
|
} catch (error) {
|
|
140
131
|
if (this.sysLogger !== undefined && this.sysLogger !== null) {
|
|
141
132
|
this.sysLogger.error(`KNXUltimatehueEngine: loadResourcesFromHUEBridge: ${error.message}`);
|
|
142
|
-
|
|
133
|
+
return (error.message);
|
|
143
134
|
}
|
|
144
135
|
}
|
|
136
|
+
return true;
|
|
145
137
|
})();
|
|
146
|
-
}
|
|
138
|
+
};
|
|
139
|
+
|
|
147
140
|
// Returns the cached devices (node.hueAllResources) by type.
|
|
148
|
-
node.getResources = (_rtype)
|
|
141
|
+
node.getResources = function getResources(_rtype) {
|
|
149
142
|
try {
|
|
150
143
|
if (node.hueAllResources === undefined) return;
|
|
151
144
|
// Returns capitalized string
|
|
@@ -260,34 +253,43 @@ module.exports = (RED) => {
|
|
|
260
253
|
};
|
|
261
254
|
|
|
262
255
|
// Query HUE Bridge and get the updated color.
|
|
263
|
-
node.getColorFromHueLight = (_lightId) =>
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
} catch (error) {
|
|
275
|
-
if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.error(`KNXUltimateHue: hueEngine: getColorFromHueLight: error ${error.message}`);
|
|
276
|
-
reject(error.message);
|
|
277
|
-
}
|
|
278
|
-
})();
|
|
279
|
-
});
|
|
256
|
+
node.getColorFromHueLight = (_lightId) => {
|
|
257
|
+
try {
|
|
258
|
+
// await node.loadResourcesFromHUEBridge();
|
|
259
|
+
const oLight = node.hueAllResources.filter((a) => a.id === _lightId)[0];
|
|
260
|
+
const ret = hueColorConverter.ColorConverter.xyBriToRgb(oLight.color.xy.x, oLight.color.xy.y, oLight.dimming.brightness);
|
|
261
|
+
return JSON.stringify(ret);
|
|
262
|
+
} catch (error) {
|
|
263
|
+
if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.error(`KNXUltimateHue: hueEngine: getColorFromHueLight: error ${error.message}`);
|
|
264
|
+
return {};
|
|
265
|
+
}
|
|
266
|
+
};
|
|
280
267
|
|
|
281
268
|
node.addClient = (_Node) => {
|
|
282
|
-
//
|
|
283
|
-
if (node.
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
269
|
+
// Update the node hue device, as soon as a node register itself to hue-config nodeClients
|
|
270
|
+
if (node.hueAllResources !== null) {
|
|
271
|
+
if (node.nodeClients.filter((x) => x.id === _Node.id).length === 0) { // At first start, due to the async method for retrieving hueAllResources, hueAllResources is still null. The first start is handled in node.hueManager.on("connected")
|
|
272
|
+
const oHUEDevice = node.hueAllResources.filter((a) => a.id === _Node.hueDevice)[0];
|
|
273
|
+
_Node.currentHUEDevice = oHUEDevice;
|
|
274
|
+
if (oHUEDevice !== undefined) _Node.handleSendHUE(oHUEDevice);
|
|
275
|
+
node.nodeClients.push(_Node);
|
|
276
|
+
// Add _Node to the clients array
|
|
277
|
+
_Node.setNodeStatusHue({
|
|
278
|
+
fill: "green",
|
|
279
|
+
shape: "ring",
|
|
280
|
+
text: "Ready",
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
} else {
|
|
284
|
+
if (node.nodeClientsAwaitingInit.filter((x) => x.id === _Node.id).length === 0) {
|
|
285
|
+
// Put the node in the waiting list
|
|
286
|
+
node.nodeClientsAwaitingInit.push(_Node);
|
|
287
|
+
_Node.setNodeStatusHue({
|
|
288
|
+
fill: "grey",
|
|
289
|
+
shape: "dot",
|
|
290
|
+
text: "Awaiting HUE Resources",
|
|
291
|
+
});
|
|
292
|
+
}
|
|
291
293
|
}
|
|
292
294
|
};
|
|
293
295
|
|
|
@@ -295,7 +297,9 @@ module.exports = (RED) => {
|
|
|
295
297
|
// Remove the client node from the clients array
|
|
296
298
|
try {
|
|
297
299
|
node.nodeClients = node.nodeClients.filter((x) => x.id !== _Node.id);
|
|
298
|
-
} catch (error) {
|
|
300
|
+
} catch (error) {
|
|
301
|
+
/* empty */
|
|
302
|
+
}
|
|
299
303
|
};
|
|
300
304
|
|
|
301
305
|
node.on("close", (done) => {
|
|
@@ -320,14 +324,12 @@ module.exports = (RED) => {
|
|
|
320
324
|
});
|
|
321
325
|
|
|
322
326
|
RED.httpAdmin.get("/knxUltimateGetHueColor", RED.auth.needsPermission("hue-config.read"), (req, res) => {
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
}
|
|
330
|
-
})();
|
|
327
|
+
try {
|
|
328
|
+
const rgbColor = node.getColorFromHueLight(req.query.id);
|
|
329
|
+
res.json(rgbColor);
|
|
330
|
+
} catch (error) {
|
|
331
|
+
res.json("Select the device first!");
|
|
332
|
+
}
|
|
331
333
|
});
|
|
332
334
|
|
|
333
335
|
RED.httpAdmin.get("/KNXUltimateGetResourcesHUE", RED.auth.needsPermission("hue-config.read"), (req, res) => {
|
|
@@ -347,8 +349,7 @@ module.exports = (RED) => {
|
|
|
347
349
|
});
|
|
348
350
|
|
|
349
351
|
RED.httpAdmin.get("/knxUltimateDpts", RED.auth.needsPermission("hue-config.read"), (req, res) => {
|
|
350
|
-
const dpts = Object.entries(dptlib).filter(onlyDptKeys).map(extractBaseNo).sort(sortBy("base"))
|
|
351
|
-
.reduce(toConcattedSubtypes, []);
|
|
352
|
+
const dpts = Object.entries(dptlib).filter(onlyDptKeys).map(extractBaseNo).sort(sortBy("base")).reduce(toConcattedSubtypes, []);
|
|
352
353
|
res.json(dpts);
|
|
353
354
|
});
|
|
354
355
|
}
|
|
@@ -940,14 +940,16 @@ return msg;`,
|
|
|
940
940
|
}
|
|
941
941
|
// 12/11/2021 Starts the telegram out queue handler
|
|
942
942
|
if (node.timerSendTelegramFromQueue !== null) clearInterval(node.timerSendTelegramFromQueue);
|
|
943
|
-
node.timerSendTelegramFromQueue = setInterval(handleTelegramQueue, config.delaybetweentelegrams === undefined || Number(config.delaybetweentelegrams) < 20 ? 20 : Number(config.delaybetweentelegrams)
|
|
944
|
-
); // 02/01/2020 Start the timer that handles the queue of telegrams
|
|
943
|
+
node.timerSendTelegramFromQueue = setInterval(handleTelegramQueue, config.delaybetweentelegrams === undefined || Number(config.delaybetweentelegrams) < 20 ? 20 : Number(config.delaybetweentelegrams)); // 02/01/2020 Start the timer that handles the queue of telegrams
|
|
945
944
|
node.linkStatus = "connected";
|
|
946
945
|
|
|
947
946
|
// Start the timer to do initial read.
|
|
948
947
|
if (node.timerDoInitialRead !== null) clearTimeout(node.timerDoInitialRead);
|
|
949
|
-
node.timerDoInitialRead = setTimeout(
|
|
950
|
-
|
|
948
|
+
node.timerDoInitialRead = setTimeout(() => {
|
|
949
|
+
DoInitialReadFromKNXBusOrFile();
|
|
950
|
+
callConnectToHueBridgeOfAllHUEServers();
|
|
951
|
+
}, 6000); // 17/02/2020 Do initial read of all nodes requesting initial read
|
|
952
|
+
//node.timerCallConnectToHueBridgeOfAllHUEServers = setTimeout(callConnectToHueBridgeOfAllHUEServers, 6000); // connects all hue-config nodes to the HUE Bridge.
|
|
951
953
|
const t = setTimeout(() => {
|
|
952
954
|
// 21/03/2022 fixed possible memory leak. Previously was setTimeout without "let t = ".
|
|
953
955
|
node.setAllClientsStatus("Connected.", "green", "On duty.");
|
|
@@ -1,107 +1,108 @@
|
|
|
1
1
|
module.exports = function (RED) {
|
|
2
2
|
function knxUltimateHueBattery(config) {
|
|
3
|
-
RED.nodes.createNode(this, config)
|
|
4
|
-
const node = this
|
|
5
|
-
node.server = RED.nodes.getNode(config.server)
|
|
6
|
-
node.serverHue = RED.nodes.getNode(config.serverHue)
|
|
7
|
-
node.topic = node.name
|
|
8
|
-
node.name = config.name === undefined ? 'Hue' : config.name
|
|
9
|
-
node.dpt = ''
|
|
10
|
-
node.notifyreadrequest = false
|
|
11
|
-
node.notifyreadrequestalsorespondtobus = 'false'
|
|
12
|
-
node.notifyreadrequestalsorespondtobusdefaultvalueifnotinitialized = ''
|
|
13
|
-
node.notifyresponse = false
|
|
14
|
-
node.notifywrite = true
|
|
15
|
-
node.initialread = true
|
|
16
|
-
node.listenallga = true // Don't remove
|
|
17
|
-
node.outputtype = 'write'
|
|
18
|
-
node.outputRBE = false // Apply or not RBE to the output (Messages coming from flow)
|
|
19
|
-
node.inputRBE = false // Apply or not RBE to the input (Messages coming from BUS)
|
|
20
|
-
node.currentPayload = '' // Current value for the RBE input and for the .previouspayload msg
|
|
21
|
-
node.passthrough = 'no'
|
|
22
|
-
node.formatmultiplyvalue = 1
|
|
23
|
-
node.formatnegativevalue = 'leave'
|
|
24
|
-
node.formatdecimalsvalue = 2
|
|
3
|
+
RED.nodes.createNode(this, config);
|
|
4
|
+
const node = this;
|
|
5
|
+
node.server = RED.nodes.getNode(config.server);
|
|
6
|
+
node.serverHue = RED.nodes.getNode(config.serverHue);
|
|
7
|
+
node.topic = node.name;
|
|
8
|
+
node.name = config.name === undefined ? 'Hue' : config.name;
|
|
9
|
+
node.dpt = '';
|
|
10
|
+
node.notifyreadrequest = false;
|
|
11
|
+
node.notifyreadrequestalsorespondtobus = 'false';
|
|
12
|
+
node.notifyreadrequestalsorespondtobusdefaultvalueifnotinitialized = '';
|
|
13
|
+
node.notifyresponse = false;
|
|
14
|
+
node.notifywrite = true;
|
|
15
|
+
node.initialread = true;
|
|
16
|
+
node.listenallga = true; // Don't remove
|
|
17
|
+
node.outputtype = 'write';
|
|
18
|
+
node.outputRBE = false; // Apply or not RBE to the output (Messages coming from flow)
|
|
19
|
+
node.inputRBE = false; // Apply or not RBE to the input (Messages coming from BUS)
|
|
20
|
+
node.currentPayload = ''; // Current value for the RBE input and for the .previouspayload msg
|
|
21
|
+
node.passthrough = 'no';
|
|
22
|
+
node.formatmultiplyvalue = 1;
|
|
23
|
+
node.formatnegativevalue = 'leave';
|
|
24
|
+
node.formatdecimalsvalue = 2;
|
|
25
25
|
|
|
26
26
|
// Used to call the status update from the config node.
|
|
27
|
-
node.setNodeStatus = ({
|
|
27
|
+
node.setNodeStatus = ({
|
|
28
|
+
fill, shape, text, payload,
|
|
29
|
+
}) => {
|
|
28
30
|
|
|
29
|
-
}
|
|
31
|
+
};
|
|
30
32
|
// Used to call the status update from the HUE config node.
|
|
31
|
-
node.setNodeStatusHue = ({
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
payload
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
node.setNodeStatusHue = ({
|
|
34
|
+
fill, shape, text, payload,
|
|
35
|
+
}) => {
|
|
36
|
+
if (payload === undefined) payload = '';
|
|
37
|
+
const dDate = new Date();
|
|
38
|
+
payload = typeof payload === 'object' ? JSON.stringify(payload) : payload.toString();
|
|
39
|
+
node.status({ fill, shape, text: `${text} ${payload} (${dDate.getDate()}, ${dDate.toLocaleTimeString()})` });
|
|
40
|
+
};
|
|
37
41
|
|
|
38
42
|
// This function is called by the knx-ultimate config node, to output a msg.payload.
|
|
39
|
-
node.handleSend = msg => {
|
|
40
|
-
}
|
|
43
|
+
node.handleSend = (msg) => {
|
|
44
|
+
};
|
|
41
45
|
|
|
42
|
-
node.handleSendHUE = _event => {
|
|
46
|
+
node.handleSendHUE = (_event) => {
|
|
43
47
|
try {
|
|
44
48
|
if (_event.id === config.hueDevice) {
|
|
45
|
-
const knxMsgPayload = {}
|
|
46
|
-
knxMsgPayload.topic = config.GAbatterysensor
|
|
47
|
-
knxMsgPayload.dpt = config.dptbatterysensor
|
|
49
|
+
const knxMsgPayload = {};
|
|
50
|
+
knxMsgPayload.topic = config.GAbatterysensor;
|
|
51
|
+
knxMsgPayload.dpt = config.dptbatterysensor;
|
|
48
52
|
|
|
49
53
|
if (_event.hasOwnProperty('power_state') && _event.power_state.hasOwnProperty('battery_level')) {
|
|
50
|
-
knxMsgPayload.payload = _event.power_state.battery_level
|
|
54
|
+
knxMsgPayload.payload = _event.power_state.battery_level;
|
|
51
55
|
// Send to KNX bus
|
|
52
|
-
if (knxMsgPayload.topic !== '' && knxMsgPayload.topic !== undefined)
|
|
53
|
-
|
|
56
|
+
if (knxMsgPayload.topic !== '' && knxMsgPayload.topic !== undefined) {
|
|
57
|
+
node.server.writeQueueAdd({
|
|
58
|
+
grpaddr: knxMsgPayload.topic, payload: knxMsgPayload.payload, dpt: knxMsgPayload.dpt, outputtype: 'write', nodecallerid: node.id,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
54
62
|
// Setup the output msg
|
|
55
|
-
knxMsgPayload.name = node.name
|
|
56
|
-
knxMsgPayload.event = 'power_state'
|
|
63
|
+
knxMsgPayload.name = node.name;
|
|
64
|
+
knxMsgPayload.event = 'power_state';
|
|
57
65
|
|
|
58
66
|
// Send payload
|
|
59
|
-
knxMsgPayload.rawEvent = _event
|
|
60
|
-
node.send(knxMsgPayload)
|
|
61
|
-
node.setNodeStatusHue({
|
|
67
|
+
knxMsgPayload.rawEvent = _event;
|
|
68
|
+
node.send(knxMsgPayload);
|
|
69
|
+
node.setNodeStatusHue({
|
|
70
|
+
fill: 'blue', shape: 'ring', text: 'HUE->KNX', payload: knxMsgPayload.payload,
|
|
71
|
+
});
|
|
62
72
|
}
|
|
63
73
|
}
|
|
64
74
|
} catch (error) {
|
|
65
|
-
node.status({ fill: 'red', shape: 'dot', text:
|
|
75
|
+
node.status({ fill: 'red', shape: 'dot', text: `HUE->KNX error ${error.message} (${new Date().getDate()}, ${new Date().toLocaleTimeString()})` });
|
|
66
76
|
}
|
|
67
|
-
}
|
|
77
|
+
};
|
|
68
78
|
|
|
69
79
|
// On each deploy, unsubscribe+resubscribe
|
|
70
80
|
if (node.server) {
|
|
71
|
-
node.server.removeClient(node)
|
|
72
|
-
node.server.addClient(node)
|
|
81
|
+
node.server.removeClient(node);
|
|
82
|
+
node.server.addClient(node);
|
|
73
83
|
}
|
|
74
84
|
if (node.serverHue) {
|
|
75
|
-
node.serverHue.removeClient(node)
|
|
85
|
+
node.serverHue.removeClient(node);
|
|
76
86
|
// I must get the object, to store read the battery status
|
|
77
87
|
// I queue the state request, by passing the callback to call whenever the HUE bridge send me the light status async
|
|
78
88
|
if (node.serverHue !== null && node.serverHue.hueManager !== null) {
|
|
79
|
-
(
|
|
80
|
-
try {
|
|
81
|
-
node.serverHue.addClient(node)
|
|
82
|
-
await node.serverHue.hueManager.writeHueQueueAdd(config.hueDevice, null, 'getBattery', (jLight) => {
|
|
83
|
-
node.handleSendHUE(jLight)
|
|
84
|
-
})
|
|
85
|
-
} catch (err) {
|
|
86
|
-
RED.log.error('Errore knxUltimateHueBattery subscribe: ' + err.message)
|
|
87
|
-
}
|
|
88
|
-
})()
|
|
89
|
+
node.serverHue.addClient(node);
|
|
89
90
|
}
|
|
90
91
|
}
|
|
91
92
|
|
|
92
|
-
node.on('input',
|
|
93
|
+
node.on('input', (msg) => {
|
|
93
94
|
|
|
94
|
-
})
|
|
95
|
+
});
|
|
95
96
|
|
|
96
|
-
node.on('close',
|
|
97
|
+
node.on('close', (done) => {
|
|
97
98
|
if (node.server) {
|
|
98
|
-
node.server.removeClient(node)
|
|
99
|
+
node.server.removeClient(node);
|
|
99
100
|
}
|
|
100
101
|
if (node.serverHue) {
|
|
101
|
-
node.serverHue.removeClient(node)
|
|
102
|
+
node.serverHue.removeClient(node);
|
|
102
103
|
}
|
|
103
|
-
done()
|
|
104
|
-
})
|
|
104
|
+
done();
|
|
105
|
+
});
|
|
105
106
|
}
|
|
106
|
-
RED.nodes.registerType('knxUltimateHueBattery', knxUltimateHueBattery)
|
|
107
|
-
}
|
|
107
|
+
RED.nodes.registerType('knxUltimateHueBattery', knxUltimateHueBattery);
|
|
108
|
+
};
|
|
@@ -37,7 +37,7 @@ module.exports = function (RED) {
|
|
|
37
37
|
node.setNodeStatusHue = ({
|
|
38
38
|
fill, shape, text, payload,
|
|
39
39
|
}) => {
|
|
40
|
-
if (payload === undefined)
|
|
40
|
+
if (payload === undefined) payload = '';
|
|
41
41
|
const dDate = new Date();
|
|
42
42
|
payload = typeof payload === 'object' ? JSON.stringify(payload) : payload.toString();
|
|
43
43
|
node.status({ fill, shape, text: `${text} ${payload} (${dDate.getDate()}, ${dDate.toLocaleTimeString()})` });
|
|
@@ -1,4 +1,24 @@
|
|
|
1
1
|
<script type="text/javascript">
|
|
2
|
+
RED.events.on('nodes:add', function (node) {
|
|
3
|
+
if (node.type === 'uibuilder') {
|
|
4
|
+
// Keep a list of uib nodes in the editor
|
|
5
|
+
// may be different to the deployed list
|
|
6
|
+
editorInstances[node.id] = node.url
|
|
7
|
+
// -- IF uibuilderInstances <> editorInstances THEN there are undeployed instances. --
|
|
8
|
+
}
|
|
9
|
+
})
|
|
10
|
+
RED.events.on('nodes:change', function (node) {
|
|
11
|
+
if (node.type === 'uibuilder') {
|
|
12
|
+
mylog('nodes:change:', node)
|
|
13
|
+
editorInstances[node.id] = node.url
|
|
14
|
+
}
|
|
15
|
+
})
|
|
16
|
+
RED.events.on('nodes:remove', function (node) {
|
|
17
|
+
if (node.type === 'uibuilder') {
|
|
18
|
+
mylog('>> nodes:remove >>', node)
|
|
19
|
+
delete editorInstances[node.id]
|
|
20
|
+
}
|
|
21
|
+
})
|
|
2
22
|
RED.nodes.registerType("knxUltimateHueLight", {
|
|
3
23
|
category: "KNX Ultimate",
|
|
4
24
|
color: "#C0C7E9",
|
|
@@ -66,7 +86,7 @@
|
|
|
66
86
|
dptDaylightSensor: { value: "" },
|
|
67
87
|
|
|
68
88
|
specifySwitchOnBrightness: { value: "yes" },
|
|
69
|
-
updateKNXBrightnessStatusOnHUEOnOff: { value: "
|
|
89
|
+
updateKNXBrightnessStatusOnHUEOnOff: { value: "no" },
|
|
70
90
|
dimSpeed: { value: 5000, required: false },
|
|
71
91
|
minDimLevelLight: { value: 10, required: false },
|
|
72
92
|
maxDimLevelLight: { value: 100, required: false },
|
|
@@ -486,15 +506,15 @@
|
|
|
486
506
|
$("#getColorAtSwitchOnNightTimeButton").text("Get current");
|
|
487
507
|
});
|
|
488
508
|
});
|
|
489
|
-
|
|
509
|
+
|
|
490
510
|
// Fill options for minDimLevel and maxDimLevel
|
|
491
511
|
for (let index = 0; index <= 90; index++) {
|
|
492
|
-
if (index === 0){
|
|
512
|
+
if (index === 0) {
|
|
493
513
|
$("#node-input-minDimLevelLight").append($("<option>").val(index).text(index.toString() + "% (Switch Off)"));
|
|
494
|
-
}else{
|
|
514
|
+
} else {
|
|
495
515
|
$("#node-input-minDimLevelLight").append($("<option>").val(index).text(index.toString() + "%"));
|
|
496
516
|
}
|
|
497
|
-
|
|
517
|
+
|
|
498
518
|
}
|
|
499
519
|
$("#node-input-minDimLevelLight").val(node.minDimLevelLight);
|
|
500
520
|
for (let index = 100; index >= 10; index--) {
|