node-red-contrib-knx-ultimate 2.1.63 → 2.2.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.
- package/.eslintrc.json +12 -12
- package/CHANGELOG.md +17 -1
- package/KNXEngine/package.json +1 -1
- package/nodes/hue-config.html +2 -2
- package/nodes/hue-config.js +81 -39
- package/nodes/knxUltimate-config.js +158 -156
- package/nodes/knxUltimateHueBattery.html +2 -2
- package/nodes/knxUltimateHueButton.html +1 -1
- package/nodes/knxUltimateHueButton.js +152 -116
- package/nodes/knxUltimateHueLight.html +830 -781
- package/nodes/knxUltimateHueLight.js +145 -149
- package/nodes/knxUltimateHueLightSensor.html +1 -1
- package/nodes/knxUltimateHueLightSensor.js +2 -2
- package/nodes/knxUltimateHueMotion.html +3 -4
- package/nodes/knxUltimateHueMotion.js +73 -61
- package/nodes/knxUltimateHueScene.html +1 -1
- package/nodes/knxUltimateHueScene.js +1 -1
- package/nodes/knxUltimateHueTapDial.html +1 -1
- package/nodes/knxUltimateHueTapDial.js +1 -2
- package/nodes/knxUltimateHueTemperatureSensor.html +2 -2
- package/nodes/knxUltimateLoadControl.html +1 -1
- package/nodes/knxUltimateViewer.html +28 -0
- package/nodes/utils/hueEngine.js +5 -25
- package/package.json +26 -5
- package/nodes/utils/iro.js +0 -1835
package/.eslintrc.json
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
2
|
+
"env": {
|
|
3
|
+
"browser": true,
|
|
4
|
+
"commonjs": true,
|
|
5
|
+
"es2021": true
|
|
6
|
+
},
|
|
7
|
+
"extends": "airbnb-base",
|
|
8
|
+
"parserOptions": {
|
|
9
|
+
"ecmaVersion": "latest"
|
|
10
|
+
},
|
|
11
|
+
"rules": {
|
|
12
|
+
"quotes": "off"
|
|
13
|
+
}
|
|
14
14
|
}
|
package/CHANGELOG.md
CHANGED
|
@@ -1,10 +1,26 @@
|
|
|
1
1
|

|
|
2
2
|
|
|
3
|
-
[](https://www.paypal.me/techtoday)
|
|
3
|
+
[](https://www.paypal.me/techtoday)
|
|
4
4
|
|
|
5
5
|
<br/>
|
|
6
6
|
|
|
7
7
|
# CHANGELOG
|
|
8
|
+
|
|
9
|
+
<p>
|
|
10
|
+
<b>Version 2.2.2</b> - October 2023<br/>
|
|
11
|
+
- NEW: HUE Motion: support HUE Camera motion events via the HUE Motion node.<br/>
|
|
12
|
+
- HUE Light: some tweaking to the GUI.<br/>
|
|
13
|
+
- HUE Grouped Light: Fixed relative dimming function.<br/>
|
|
14
|
+
- KNK Alerter node: <a href="https://github.com/Supergiovane/node-red-contrib-knx-ultimate/wiki/SampleAlerter">fixed the wiki sample page</a>.<br/>
|
|
15
|
+
- KNX Viewer: added the help pane in Node-Red.<br/>
|
|
16
|
+
</p>
|
|
17
|
+
<p>
|
|
18
|
+
<b>Version 2.2.1</b> - October 2023<br/>
|
|
19
|
+
- Massive rewrite of the DIM function, for brightness and for color temperature.<br/>
|
|
20
|
+
- NEW: HUE Light: Added dimming speed, minimum dim value and maximum dim value.<br/>
|
|
21
|
+
- NEW: HUE Light: Read of the lamp status at node-red start and after deploy of a new node.<br/>
|
|
22
|
+
- Security fix: patched a vulnerability in crypto.js.<br/>
|
|
23
|
+
</p>
|
|
8
24
|
<p>
|
|
9
25
|
<b>Version 2.1.63</b> - October 2023<br/>
|
|
10
26
|
- HUE Light: optimized the GUI in select color TAB.<br/>
|
package/KNXEngine/package.json
CHANGED
package/nodes/hue-config.html
CHANGED
|
@@ -129,8 +129,8 @@
|
|
|
129
129
|
|
|
130
130
|
|
|
131
131
|
</script>
|
|
132
|
-
<script type="text/markdown" data-help-name="hue-config"
|
|
133
|
-
|
|
132
|
+
<script type="text/markdown" data-help-name="hue-config"
|
|
133
|
+
This node registers to the Hue Bridge.
|
|
134
134
|
|
|
135
135
|
Just set the Bridge's IP and click **CONNECT** button.
|
|
136
136
|
|
package/nodes/hue-config.js
CHANGED
|
@@ -35,12 +35,13 @@ const toConcattedSubtypes = (acc, baseType) => {
|
|
|
35
35
|
return acc.concat(subtypes);
|
|
36
36
|
};
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
38
|
+
function getRandomInt(min, max) {
|
|
39
|
+
min = Math.ceil(min);
|
|
40
|
+
max = Math.floor(max);
|
|
41
|
+
return Math.floor(Math.random() * (max - min) + min); // The maximum is exclusive and the minimum is inclusive
|
|
42
|
+
}
|
|
43
43
|
|
|
44
|
+
module.exports = (RED) => {
|
|
44
45
|
function hueConfig(config) {
|
|
45
46
|
RED.nodes.createNode(this, config);
|
|
46
47
|
const node = this;
|
|
@@ -48,6 +49,7 @@ module.exports = (RED) => {
|
|
|
48
49
|
node.nodeClients = []; // Stores the registered clients
|
|
49
50
|
node.loglevel = config.loglevel !== undefined ? config.loglevel : "error"; // 18/02/2020 Loglevel default error
|
|
50
51
|
node.sysLogger = null;
|
|
52
|
+
node.hueAllResources = null;
|
|
51
53
|
try {
|
|
52
54
|
node.sysLogger = loggerEngine.get({ loglevel: node.loglevel }); // New logger to adhere to the loglevel selected in the config-window
|
|
53
55
|
} catch (error) {
|
|
@@ -80,20 +82,72 @@ module.exports = (RED) => {
|
|
|
80
82
|
});
|
|
81
83
|
// Connected
|
|
82
84
|
node.hueManager.on("connected", () => {
|
|
85
|
+
(async () => {
|
|
86
|
+
try {
|
|
87
|
+
await node.loadResourcesFromHUEBridge(); // Then, you can use node.getResources, that works locally and doesn't query the HUE Bridge.
|
|
88
|
+
} catch (error) { /* empty */ }
|
|
89
|
+
})();
|
|
83
90
|
if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.info("node.hueManager connected event");
|
|
84
91
|
});
|
|
85
|
-
// Initialize the http wrapper, to use the provided key.
|
|
86
|
-
// This http wrapper is used to get the data from HUE brigde
|
|
87
|
-
await node.refreshResources();
|
|
88
92
|
};
|
|
89
93
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
94
|
+
// Query the HUE Bridge to return the resources
|
|
95
|
+
node.loadResourcesFromHUEBridge = (_callerNode = undefined) => new Promise((resolve, reject) => {
|
|
96
|
+
(async () => {
|
|
97
|
+
// °°°°°° Load ALL resources
|
|
98
|
+
try {
|
|
99
|
+
if (_callerNode === undefined) {
|
|
100
|
+
node.hueAllResources = await node.hueManager.hueApiV2.get("/resource");
|
|
101
|
+
node.hueAllRooms = node.hueAllResources.filter((a) => a.type === "room");
|
|
102
|
+
// Update all KNX State of the nodes with the new hue device values
|
|
103
|
+
node.nodeClients.forEach((nodeClient) => {
|
|
104
|
+
if (nodeClient.hueDevice !== undefined) {
|
|
105
|
+
const oHUEDevice = node.hueAllResources.filter((a) => a.id === nodeClient.hueDevice)[0];
|
|
106
|
+
if (oHUEDevice !== undefined) {
|
|
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
|
+
}
|
|
116
|
+
});
|
|
117
|
+
} else {
|
|
118
|
+
// °°°°°° Read ONE resource and update only one node. The node is requesting an update because it has been edited in Node-Red's window by the user
|
|
119
|
+
try {
|
|
120
|
+
// Please KEEP THE AWAIT, otherwise al posto dell'oggetto, a Promisse will be returned.
|
|
121
|
+
const oHUEDevice = await node.hueAllResources.filter((a) => a.id === _callerNode.hueDevice)[0];
|
|
122
|
+
if (oHUEDevice !== undefined) {
|
|
123
|
+
_callerNode.currentHUEDevice = oHUEDevice;
|
|
124
|
+
for (const [key, value] of Object.entries(oHUEDevice)) {
|
|
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);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
resolve(true);
|
|
139
|
+
} catch (error) {
|
|
140
|
+
if (this.sysLogger !== undefined && this.sysLogger !== null) {
|
|
141
|
+
this.sysLogger.error(`KNXUltimatehueEngine: loadResourcesFromHUEBridge: ${error.message}`);
|
|
142
|
+
reject(error.message);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
})();
|
|
146
|
+
});
|
|
147
|
+
// Returns the cached devices (node.hueAllResources) by type.
|
|
95
148
|
node.getResources = (_rtype) => {
|
|
96
149
|
try {
|
|
150
|
+
if (node.hueAllResources === undefined) return;
|
|
97
151
|
// Returns capitalized string
|
|
98
152
|
function capStr(s) {
|
|
99
153
|
if (typeof s !== "string") return "";
|
|
@@ -121,14 +175,14 @@ module.exports = (RED) => {
|
|
|
121
175
|
resourceName += "ALL GROUPS and ";
|
|
122
176
|
} else {
|
|
123
177
|
resourceName += `${owner.metadata.name} and `;
|
|
124
|
-
//const room = node.hueAllRooms.find((child) => child.children.find((a) => a.rid === owner.id));
|
|
125
|
-
//sRoom += room !== undefined ? `${room.metadata.name} + ` : " + ";
|
|
126
|
-
sType += capStr(owner.type) +
|
|
178
|
+
// const room = node.hueAllRooms.find((child) => child.children.find((a) => a.rid === owner.id));
|
|
179
|
+
// sRoom += room !== undefined ? `${room.metadata.name} + ` : " + ";
|
|
180
|
+
sType += `${capStr(owner.type)} + `;
|
|
127
181
|
}
|
|
128
182
|
}
|
|
129
183
|
sType = sType.slice(0, -" + ".length);
|
|
130
184
|
resourceName = resourceName.slice(0, -" and ".length);
|
|
131
|
-
resourceName += sType !== "" ?
|
|
185
|
+
resourceName += sType !== "" ? ` (${sType})` : "";
|
|
132
186
|
retArray.push({
|
|
133
187
|
name: `${capStr(resource.type)}: ${resourceName}`,
|
|
134
188
|
id: resource.id,
|
|
@@ -153,7 +207,7 @@ module.exports = (RED) => {
|
|
|
153
207
|
id: resource.id,
|
|
154
208
|
});
|
|
155
209
|
}
|
|
156
|
-
if (_rtype === "motion") {
|
|
210
|
+
if (_rtype === "motion" || _rtype === "camera_motion") {
|
|
157
211
|
const linkedDevName = node.hueAllResources.find((dev) => dev.type === "device" && dev.services.find((serv) => serv.rid === resource.id)).metadata.name || "";
|
|
158
212
|
retArray.push({
|
|
159
213
|
name: `${capStr(_rtype)}: ${linkedDevName}`,
|
|
@@ -200,32 +254,16 @@ module.exports = (RED) => {
|
|
|
200
254
|
}
|
|
201
255
|
return { devices: retArray };
|
|
202
256
|
} catch (error) {
|
|
203
|
-
if (node.sysLogger !== undefined && node.sysLogger !== null)
|
|
204
|
-
node.sysLogger.error(`KNXUltimateHue: hueEngine: classHUE: getDevices: error ${error.message}`);
|
|
257
|
+
if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.error(`KNXUltimateHue: hueEngine: classHUE: getResources: error ${error.message}`);
|
|
205
258
|
return { devices: error.message };
|
|
206
259
|
}
|
|
207
260
|
};
|
|
208
|
-
node.refreshResources = () => new Promise((resolve, reject) => {
|
|
209
|
-
(async () => {
|
|
210
|
-
// Reload all resources
|
|
211
|
-
try {
|
|
212
|
-
node.hueAllResources = await node.hueManager.hueApiV2.get("/resource");
|
|
213
|
-
node.hueAllRooms = node.hueAllResources.filter((a) => a.type === "room");
|
|
214
|
-
resolve(true);
|
|
215
|
-
} catch (error) {
|
|
216
|
-
if (this.sysLogger !== undefined && this.sysLogger !== null) {
|
|
217
|
-
this.sysLogger.error(`KNXUltimatehueEngine: getting resources: ${error.message}`);
|
|
218
|
-
reject(error.message);
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
})();
|
|
222
|
-
});
|
|
223
261
|
|
|
224
|
-
//
|
|
262
|
+
// Query HUE Bridge and get the updated color.
|
|
225
263
|
node.getColorFromHueLight = (_lightId) => new Promise((resolve, reject) => {
|
|
226
264
|
(async () => {
|
|
227
265
|
try {
|
|
228
|
-
await node.
|
|
266
|
+
// await node.loadResourcesFromHUEBridge();
|
|
229
267
|
const oLight = node.hueAllResources.filter((a) => a.id === _lightId)[0];
|
|
230
268
|
const ret = hueColorConverter.ColorConverter.xyBriToRgb(
|
|
231
269
|
oLight.color.xy.x,
|
|
@@ -307,9 +345,13 @@ module.exports = (RED) => {
|
|
|
307
345
|
})();
|
|
308
346
|
}
|
|
309
347
|
});
|
|
310
|
-
}
|
|
311
348
|
|
|
312
|
-
|
|
349
|
+
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
|
+
res.json(dpts);
|
|
353
|
+
});
|
|
354
|
+
}
|
|
313
355
|
RED.nodes.registerType("hue-config", hueConfig, {
|
|
314
356
|
credentials: {
|
|
315
357
|
username: { type: "password" },
|