node-red-contrib-knx-ultimate 2.4.5-beta.0 → 2.4.5-beta.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/CHANGELOG.md +11 -0
- package/KNXEngine/CHANGELOG.md +1 -1
- package/KNXEngine/README.md +35 -5
- package/KNXEngine/package.json +1 -1
- package/KNXEngine/sample.js +10 -1
- package/KNXEngine/simpleSample.js +8 -5
- package/nodes/commonFunctions.js +2 -2
- package/nodes/hue-config.js +13 -79
- package/nodes/knxUltimateHueLight.html +187 -37
- package/nodes/knxUltimateHueLight.js +344 -16
- package/nodes/utils/colorManipulators/XYFromRGB_Supergiovane.js +108 -0
- package/nodes/utils/colorManipulators/hueColorConverter.js +516 -0
- package/nodes/utils/hueEngine.js +10 -0
- package/package.json +1 -31
- package/resources/dim.png +0 -0
- package/resources/rgb.png +0 -0
- package/resources/tunablewhite.png +0 -0
- package/nodes/utils/hueColorConverter.js +0 -410
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,17 @@
|
|
|
6
6
|
|
|
7
7
|
# CHANGELOG
|
|
8
8
|
|
|
9
|
+
**Version 2.4.5-beta.2 PUBLIC BETA** - Feb 2024<br/>
|
|
10
|
+
- Fix the listing of ethernet interfaces in the gateway config window.<br/>
|
|
11
|
+
|
|
12
|
+
**Version 2.4.5-beta.1 PUBLIC BETA** - Feb 2024<br/>
|
|
13
|
+
- WARNING: this version uses the Node-Red plugin system; the Node-Red version must be **equals or major than 3.1.1**<br/>
|
|
14
|
+
- HUE: Optimized color translation between xyBri and RGB.<br/>
|
|
15
|
+
- NEW: HUE Light node: added the HSV controls.<br/>
|
|
16
|
+
- HUE Light node: stopping the dim sequence, now clears also the HUE bridge queue commands, to allow stopping the dimmer quickly.<br/>
|
|
17
|
+
- HUE Light node: smoother dimming.<br/>
|
|
18
|
+
- PLEASE TRY THIS VERSION AND GIVE ME ANY FEEDBACK ABOUT ISSUES YOU FIND. THANKS.<br/>
|
|
19
|
+
|
|
9
20
|
**Version 2.4.5-beta.0** - Jan 2024<br/>
|
|
10
21
|
- WARNING: this version uses the Node-Red plugin system; the Node-Red version must be **equals or major than 3.1.1**<br/>
|
|
11
22
|
- NEW: Added KNX Datapoint 275.100<br/>
|
package/KNXEngine/CHANGELOG.md
CHANGED
package/KNXEngine/README.md
CHANGED
|
@@ -161,16 +161,24 @@ knxUltimateClient.on(knx.KNXClient.KNXClientEvents.indication, function (_datagr
|
|
|
161
161
|
let _dst = _datagram.cEMIMessage.dstAddress.toString()
|
|
162
162
|
// Get the RAW Value
|
|
163
163
|
let _Rawvalue = _datagram.cEMIMessage.npdu.dataValue;
|
|
164
|
-
|
|
164
|
+
|
|
165
165
|
// Decode the telegram.
|
|
166
166
|
if (_dst === "0/1/1") {
|
|
167
|
-
// We know that 0/1/1 is a boolean DPT 1.001
|
|
167
|
+
// We know, for example, that 0/1/1 is a boolean DPT 1.001
|
|
168
168
|
dpt = dptlib.resolve("1.001");
|
|
169
169
|
jsValue = dptlib.fromBuffer(_Rawvalue, dpt)
|
|
170
170
|
} else if (_dst === "0/1/2") {
|
|
171
|
-
// We know that 0/1/2 is a
|
|
171
|
+
// We know , for example, that 0/1/2 is a DPT 232.600 Color RGB
|
|
172
172
|
dpt = dptlib.resolve("232.600");
|
|
173
173
|
jsValue = dptlib.fromBuffer(_Rawvalue, dpt)
|
|
174
|
+
} else {
|
|
175
|
+
// All others... assume they are boolean
|
|
176
|
+
dpt = dptlib.resolve("1.001");
|
|
177
|
+
jsValue = dptlib.fromBuffer(_Rawvalue, dpt)
|
|
178
|
+
if (jsValue === null) {
|
|
179
|
+
// Opppsss, it's null. It means that the datapoint isn't 1.001
|
|
180
|
+
// Raise whatever error you want.
|
|
181
|
+
}
|
|
174
182
|
}
|
|
175
183
|
console.log("src: " + _src + " dest: " + _dst, " event: " + _evt, " value: " + jsValue);
|
|
176
184
|
|
|
@@ -184,6 +192,10 @@ knxUltimateClient.on(knx.KNXClient.KNXClientEvents.connected, info => {
|
|
|
184
192
|
});
|
|
185
193
|
|
|
186
194
|
// Connect
|
|
195
|
+
try {
|
|
196
|
+
knxUltimateClient.removeAllListeners();
|
|
197
|
+
} catch (error) {
|
|
198
|
+
}
|
|
187
199
|
knxUltimateClient.Connect();
|
|
188
200
|
```
|
|
189
201
|
|
|
@@ -280,8 +292,18 @@ let knxUltimateClientProperties = {
|
|
|
280
292
|
KNXEthInterface: "Auto", // Bind to the first avaiable local interfavce. "Manual" if you wish to specify the interface (for example eth1); in this case, set the property interface to the interface name (interface:"eth1")
|
|
281
293
|
};
|
|
282
294
|
|
|
295
|
+
var knxUltimateClient;
|
|
296
|
+
|
|
297
|
+
// If you're reinstantiating a new knxUltimateClient object, you must remove all listeners.
|
|
298
|
+
// If this is the first time you instantiate tne knxUltimateClient object, this part of code throws an error into the try...catch.
|
|
299
|
+
try {
|
|
300
|
+
if (knxUltimateClient !== null) knxUltimateClient.removeAllListeners();
|
|
301
|
+
} catch (error) {
|
|
302
|
+
// New connection, do nothing.
|
|
303
|
+
}
|
|
304
|
+
|
|
283
305
|
// Let's go
|
|
284
|
-
|
|
306
|
+
knxUltimateClient = new knx.KNXClient(knxUltimateClientProperties);
|
|
285
307
|
|
|
286
308
|
// Setting handlers
|
|
287
309
|
// ######################################
|
|
@@ -368,6 +390,15 @@ function handleBusEvents(_datagram, _echoed) {
|
|
|
368
390
|
// We know that 0/1/2 is a boolean DPT 232.600 Color RGB
|
|
369
391
|
dpt = dptlib.resolve("232.600");
|
|
370
392
|
jsValue = dptlib.fromBuffer(_Rawvalue, dpt)
|
|
393
|
+
} else {
|
|
394
|
+
// All others... assume they are boolean
|
|
395
|
+
dpt = dptlib.resolve("1.001");
|
|
396
|
+
jsValue = dptlib.fromBuffer(_Rawvalue, dpt)
|
|
397
|
+
if (jsValue === null) {
|
|
398
|
+
// Is null, try if it's a numerical value
|
|
399
|
+
dpt = dptlib.resolve("5.001");
|
|
400
|
+
jsValue = dptlib.fromBuffer(_Rawvalue, dpt)
|
|
401
|
+
}
|
|
371
402
|
}
|
|
372
403
|
console.log("src: " + _src + " dest: " + _dst, " event: " + _evt, " value: " + jsValue);
|
|
373
404
|
|
|
@@ -390,7 +421,6 @@ Loading, decrypting and validating Keyring file has been done.<br/>
|
|
|
390
421
|
I'm working on the first secure handshake now.<br/>
|
|
391
422
|
|
|
392
423
|
```javascript
|
|
393
|
-
|
|
394
424
|
const knx = require("./index.js");
|
|
395
425
|
const KNXsecureKeyring = require("./src/KNXsecureKeyring.js");
|
|
396
426
|
const dptlib = require('./src/dptlib');
|
package/KNXEngine/package.json
CHANGED
package/KNXEngine/sample.js
CHANGED
|
@@ -84,9 +84,18 @@ let knxUltimateClientProperties = {
|
|
|
84
84
|
KNXEthInterface: "Auto", // Bind to the first avaiable local interfavce. "Manual" if you wish to specify the interface (for example eth1); in this case, set the property interface to the interface name (interface:"eth1")
|
|
85
85
|
};
|
|
86
86
|
|
|
87
|
+
var knxUltimateClient;
|
|
88
|
+
|
|
89
|
+
// If you're reinstantiating a new knxUltimateClient object, you must remove all listeners.
|
|
90
|
+
// If this is the first time you instantiate tne knxUltimateClient object, this part of code throws an error into the try...catch.
|
|
91
|
+
try {
|
|
92
|
+
if (knxUltimateClient !== null) knxUltimateClient.removeAllListeners();
|
|
93
|
+
} catch (error) {
|
|
94
|
+
// New connection, do nothing.
|
|
95
|
+
}
|
|
87
96
|
|
|
88
97
|
// Let's go
|
|
89
|
-
|
|
98
|
+
knxUltimateClient = new knx.KNXClient(knxUltimateClientProperties);
|
|
90
99
|
|
|
91
100
|
// Setting handlers
|
|
92
101
|
// ######################################
|
|
@@ -40,11 +40,11 @@ knxUltimateClient.on(knx.KNXClient.KNXClientEvents.indication, function (_datagr
|
|
|
40
40
|
|
|
41
41
|
// Decode the telegram.
|
|
42
42
|
if (_dst === "0/1/1") {
|
|
43
|
-
// We know that 0/1/1 is a boolean DPT 1.001
|
|
43
|
+
// We know, for example, that 0/1/1 is a boolean DPT 1.001
|
|
44
44
|
dpt = dptlib.resolve("1.001");
|
|
45
45
|
jsValue = dptlib.fromBuffer(_Rawvalue, dpt)
|
|
46
46
|
} else if (_dst === "0/1/2") {
|
|
47
|
-
// We know that 0/1/2 is a
|
|
47
|
+
// We know , for example, that 0/1/2 is a DPT 232.600 Color RGB
|
|
48
48
|
dpt = dptlib.resolve("232.600");
|
|
49
49
|
jsValue = dptlib.fromBuffer(_Rawvalue, dpt)
|
|
50
50
|
} else {
|
|
@@ -52,9 +52,8 @@ knxUltimateClient.on(knx.KNXClient.KNXClientEvents.indication, function (_datagr
|
|
|
52
52
|
dpt = dptlib.resolve("1.001");
|
|
53
53
|
jsValue = dptlib.fromBuffer(_Rawvalue, dpt)
|
|
54
54
|
if (jsValue === null) {
|
|
55
|
-
//
|
|
56
|
-
|
|
57
|
-
jsValue = dptlib.fromBuffer(_Rawvalue, dpt)
|
|
55
|
+
// Opppsss, it's null. It means that the datapoint isn't 1.001
|
|
56
|
+
// Raise whatever error you want.
|
|
58
57
|
}
|
|
59
58
|
}
|
|
60
59
|
console.log("src: " + _src + " dest: " + _dst, " event: " + _evt, " value: " + jsValue);
|
|
@@ -69,5 +68,9 @@ knxUltimateClient.on(knx.KNXClient.KNXClientEvents.connected, info => {
|
|
|
69
68
|
});
|
|
70
69
|
|
|
71
70
|
// Connect
|
|
71
|
+
try {
|
|
72
|
+
knxUltimateClient.removeAllListeners();
|
|
73
|
+
} catch (error) {
|
|
74
|
+
}
|
|
72
75
|
knxUltimateClient.Connect();
|
|
73
76
|
|
package/nodes/commonFunctions.js
CHANGED
|
@@ -53,7 +53,7 @@ module.exports = (RED) => {
|
|
|
53
53
|
type: "foo",
|
|
54
54
|
onadd: function () {
|
|
55
55
|
RED.events.on("registry:plugin-added", function (id) {
|
|
56
|
-
console.log(`my-test-plugin: plugin-added event "${id}"`)
|
|
56
|
+
//console.log(`my-test-plugin: plugin-added event "${id}"`)
|
|
57
57
|
commonFunctions();
|
|
58
58
|
});
|
|
59
59
|
}
|
|
@@ -237,9 +237,9 @@ module.exports = (RED) => {
|
|
|
237
237
|
|
|
238
238
|
// 14/08/2019 Endpoint for retrieving the ethernet interfaces
|
|
239
239
|
RED.httpAdmin.get("/knxUltimateETHInterfaces", (req, res) => {
|
|
240
|
+
const jListInterfaces = [];
|
|
240
241
|
try {
|
|
241
242
|
const oiFaces = oOS.networkInterfaces();
|
|
242
|
-
const jListInterfaces = [];
|
|
243
243
|
Object.keys(oiFaces).forEach((ifname) => {
|
|
244
244
|
// Interface with single IP
|
|
245
245
|
if (Object.keys(oiFaces[ifname]).length === 1) {
|
package/nodes/hue-config.js
CHANGED
|
@@ -1,55 +1,13 @@
|
|
|
1
|
+
/* eslint-disable camelcase */
|
|
1
2
|
/* eslint-disable no-underscore-dangle */
|
|
2
3
|
/* eslint-disable no-lonely-if */
|
|
3
4
|
/* eslint-disable no-param-reassign */
|
|
4
5
|
/* eslint-disable no-inner-declarations */
|
|
5
6
|
/* eslint-disable max-len */
|
|
6
|
-
const
|
|
7
|
+
const cloneDeep = require("lodash/cloneDeep");
|
|
7
8
|
const HueClass = require("./utils/hueEngine").classHUE;
|
|
8
9
|
const loggerEngine = require("./utils/sysLogger");
|
|
9
|
-
const hueColorConverter = require("./utils/hueColorConverter");
|
|
10
|
-
const cloneDeep = require("lodash/cloneDeep");
|
|
11
|
-
|
|
12
|
-
function getRandomIntInclusive(min, max) {
|
|
13
|
-
min = Math.ceil(min);
|
|
14
|
-
max = Math.floor(max);
|
|
15
|
-
return Math.floor(Math.random() * (max - min + 1) + min); // The maximum is inclusive and the minimum is inclusive
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
// Helpers
|
|
19
|
-
const sortBy = (field) => (a, b) => {
|
|
20
|
-
if (a[field] > b[field]) {
|
|
21
|
-
return 1;
|
|
22
|
-
}
|
|
23
|
-
return -1;
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
const onlyDptKeys = (kv) => kv[0].startsWith("DPT");
|
|
27
|
-
|
|
28
|
-
const extractBaseNo = (kv) => ({
|
|
29
|
-
subtypes: kv[1].subtypes,
|
|
30
|
-
base: parseInt(kv[1].id.replace("DPT", "")),
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
const convertSubtype = (baseType) => (kv) => {
|
|
34
|
-
const value = `${baseType.base}.${kv[0]}`;
|
|
35
|
-
// let sRet = value + " " + kv[1].name + (kv[1].unit === undefined ? "" : " (" + kv[1].unit + ")");
|
|
36
|
-
const sRet = `${value} ${kv[1].name}`;
|
|
37
|
-
return {
|
|
38
|
-
value,
|
|
39
|
-
text: sRet,
|
|
40
|
-
};
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
const toConcattedSubtypes = (acc, baseType) => {
|
|
44
|
-
const subtypes = Object.entries(baseType.subtypes).sort(sortBy(0)).map(convertSubtype(baseType));
|
|
45
|
-
return acc.concat(subtypes);
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
function getRandomInt(min, max) {
|
|
49
|
-
min = Math.ceil(min);
|
|
50
|
-
max = Math.floor(max);
|
|
51
|
-
return Math.floor(Math.random() * (max - min) + min); // The maximum is exclusive and the minimum is inclusive
|
|
52
|
-
}
|
|
10
|
+
const hueColorConverter = require("./utils/colorManipulators/hueColorConverter");
|
|
53
11
|
|
|
54
12
|
module.exports = (RED) => {
|
|
55
13
|
function hueConfig(config) {
|
|
@@ -69,33 +27,20 @@ module.exports = (RED) => {
|
|
|
69
27
|
}
|
|
70
28
|
node.name = config.name === undefined || config.name === "" ? node.host : config.name;
|
|
71
29
|
|
|
72
|
-
// Call the connect function of all hue-config nodes.
|
|
73
|
-
// function callinitHUEConnectionOfAllHUEServers() {
|
|
74
|
-
// RED.nodes.eachNode((_node) => {
|
|
75
|
-
// if (_node.type === 'hue-config') {
|
|
76
|
-
// try {
|
|
77
|
-
// RED.nodes.getNode(_node.id).initHUEConnection();
|
|
78
|
-
// } catch (error) {
|
|
79
|
-
// if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.error("callinitHUEConnectionOfAllHUEServers: Node " + _node.name + " " + error.message);
|
|
80
|
-
// }
|
|
81
|
-
// }
|
|
82
|
-
// });
|
|
83
|
-
// }
|
|
84
|
-
|
|
85
30
|
// Connect to Bridge and get the resources
|
|
86
31
|
node.initHUEConnection = async () => {
|
|
87
32
|
try {
|
|
88
33
|
if (node.hueManager !== undefined) node.hueManager.close();
|
|
89
|
-
} catch (error) { }
|
|
34
|
+
} catch (error) { /* empty */ }
|
|
90
35
|
try {
|
|
91
36
|
if (node.hueManager !== undefined) node.hueManager.removeAllListeners();
|
|
92
|
-
} catch (error) { }
|
|
37
|
+
} catch (error) { /* empty */ }
|
|
93
38
|
// Handle events
|
|
94
39
|
try {
|
|
95
40
|
try {
|
|
96
41
|
// Init HUE Utility
|
|
97
42
|
node.hueManager = new HueClass(node.host, node.credentials.username, node.credentials.clientkey, config.bridgeid, node.sysLogger);
|
|
98
|
-
} catch (error) { }
|
|
43
|
+
} catch (error) { /* empty */ }
|
|
99
44
|
node.hueManager.Connect();
|
|
100
45
|
} catch (error) {
|
|
101
46
|
if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.error(`Errore hue-config: node.initHUEConnection: ${error.message}`);
|
|
@@ -176,26 +121,15 @@ module.exports = (RED) => {
|
|
|
176
121
|
// °°°°°° Load ALL resources
|
|
177
122
|
try {
|
|
178
123
|
node.hueAllResources = await node.hueManager.hueApiV2.get("/resource");
|
|
179
|
-
|
|
180
|
-
// // DEBUG
|
|
181
|
-
// try {
|
|
182
|
-
// const fs = require('fs');
|
|
183
|
-
// const { resolve } = require('path');
|
|
184
|
-
// const content = JSON.stringify(node.hueAllResources);
|
|
185
|
-
// try {
|
|
186
|
-
// fs.writeFileSync('resources.json', content);
|
|
187
|
-
// RED.log.info("******************************* FILE WROTE IN resources.json " + resolve("resources.json"))
|
|
188
|
-
// // file written successfully
|
|
189
|
-
// } catch (error) {
|
|
190
|
-
// RED.log.error("********************************************* const content = JSON.stringify(node.hueAllResources)2222: " + error.message)
|
|
191
|
-
// }
|
|
192
|
-
// } catch (error) {
|
|
193
|
-
// RED.log.error("********************************************* const content = JSON.stringify(node.hueAllResources): " + error.message)
|
|
194
|
-
// }
|
|
195
|
-
|
|
196
|
-
|
|
197
124
|
if (node.hueAllResources !== undefined) {
|
|
198
125
|
node.hueAllRooms = node.hueAllResources.filter((a) => a.type === "room");
|
|
126
|
+
|
|
127
|
+
// Get zigbee_connectivituy
|
|
128
|
+
// const bridgeId = node.hueAllResources.filter((a) => a.bridge_id === config.bridgeid).owner.rid;
|
|
129
|
+
// const zigbee_ConnectivityID = node.hueAllResources.filter((a) => a.id === bridgeId).services.filter((a) => a.rtype === "zigbee_connectivity").rid;
|
|
130
|
+
// // connected, disconnected, connectivity_issue, unidirectional_incoming
|
|
131
|
+
// const oZigbeeConnectivityStatus = node.hueAllResources.filter((a) => a.id === zigbee_ConnectivityID).status;
|
|
132
|
+
|
|
199
133
|
// Update all KNX State of the nodes with the new hue device values
|
|
200
134
|
node.nodeClients.forEach((_node) => {
|
|
201
135
|
if (_node.hueDevice !== undefined && node.hueAllResources !== undefined) {
|