node-red-contrib-knx-ultimate 2.2.1 → 2.2.3
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 +13 -1
- package/nodes/hue-config.js +60 -71
- package/nodes/knxUltimate-config.js +6 -4
- package/nodes/knxUltimateHueBattery.js +69 -68
- package/nodes/knxUltimateHueLight.html +844 -835
- package/nodes/knxUltimateHueLight.js +147 -115
- package/nodes/knxUltimateHueLightSensor.js +53 -62
- package/nodes/knxUltimateHueMotion.html +3 -4
- package/nodes/knxUltimateHueMotion.js +73 -61
- package/nodes/knxUltimateHueScene.js +1 -1
- package/nodes/knxUltimateHueTemperatureSensor.js +70 -71
- package/nodes/knxUltimateViewer.html +28 -0
- package/nodes/utils/hueEngine.js +57 -42
- package/package.json +25 -4
|
@@ -1,95 +1,107 @@
|
|
|
1
1
|
module.exports = function (RED) {
|
|
2
2
|
function knxUltimateHueMotion(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 ?
|
|
9
|
-
node.dpt =
|
|
10
|
-
node.notifyreadrequest = false
|
|
11
|
-
node.notifyreadrequestalsorespondtobus =
|
|
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 =
|
|
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 =
|
|
21
|
-
node.passthrough =
|
|
22
|
-
node.formatmultiplyvalue = 1
|
|
23
|
-
node.formatnegativevalue =
|
|
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 = ({ fill, shape, text, payload }) => {
|
|
28
|
-
|
|
29
|
-
}
|
|
27
|
+
node.setNodeStatus = ({ fill, shape, text, payload }) => {};
|
|
30
28
|
// Used to call the status update from the HUE config node.
|
|
31
29
|
node.setNodeStatusHue = ({ fill, shape, text, payload }) => {
|
|
32
|
-
if (payload === undefined) return
|
|
33
|
-
const dDate = new Date()
|
|
34
|
-
payload = typeof payload ===
|
|
35
|
-
node.status({ fill, shape, text: text
|
|
36
|
-
}
|
|
30
|
+
if (payload === undefined) return;
|
|
31
|
+
const dDate = new Date();
|
|
32
|
+
payload = typeof payload === "object" ? JSON.stringify(payload) : payload.toString();
|
|
33
|
+
node.status({ fill, shape, text: `${text} ${payload} (${dDate.getDate()}, ${dDate.toLocaleTimeString()})` });
|
|
34
|
+
};
|
|
37
35
|
|
|
38
36
|
// This function is called by the knx-ultimate config node, to output a msg.payload.
|
|
39
|
-
node.handleSend = msg => {
|
|
40
|
-
}
|
|
37
|
+
node.handleSend = (msg) => {};
|
|
41
38
|
|
|
42
|
-
node.handleSendHUE = _event => {
|
|
39
|
+
node.handleSendHUE = (_event) => {
|
|
43
40
|
try {
|
|
44
41
|
if (_event.id === config.hueDevice) {
|
|
45
|
-
const knxMsgPayload = {}
|
|
46
|
-
knxMsgPayload.topic = config.GAmotion
|
|
47
|
-
knxMsgPayload.dpt = config.dptmotion
|
|
42
|
+
const knxMsgPayload = {};
|
|
43
|
+
knxMsgPayload.topic = config.GAmotion;
|
|
44
|
+
knxMsgPayload.dpt = config.dptmotion;
|
|
48
45
|
|
|
49
|
-
if (_event.hasOwnProperty(
|
|
50
|
-
knxMsgPayload.payload = _event.motion.motion
|
|
46
|
+
if (_event.hasOwnProperty("motion") && _event.motion.hasOwnProperty("motion")) {
|
|
47
|
+
knxMsgPayload.payload = _event.motion.motion_report.motion;
|
|
51
48
|
// Send to KNX bus
|
|
52
|
-
if (knxMsgPayload.topic !==
|
|
53
|
-
|
|
49
|
+
if (knxMsgPayload.topic !== "" && knxMsgPayload.topic !== undefined) {
|
|
50
|
+
node.server.writeQueueAdd({
|
|
51
|
+
grpaddr: knxMsgPayload.topic,
|
|
52
|
+
payload: knxMsgPayload.payload,
|
|
53
|
+
dpt: knxMsgPayload.dpt,
|
|
54
|
+
outputtype: "write",
|
|
55
|
+
nodecallerid: node.id,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
node.status({
|
|
59
|
+
fill: "green",
|
|
60
|
+
shape: "dot",
|
|
61
|
+
text: `HUE->KNX ${JSON.stringify(knxMsgPayload.payload)} (${new Date().getDate()}, ${new Date().toLocaleTimeString()})`,
|
|
62
|
+
});
|
|
54
63
|
|
|
55
64
|
// Setup the output msg
|
|
56
|
-
knxMsgPayload.name = node.name
|
|
57
|
-
knxMsgPayload.event =
|
|
65
|
+
knxMsgPayload.name = node.name;
|
|
66
|
+
knxMsgPayload.event = "motion";
|
|
58
67
|
|
|
59
68
|
// Send payload
|
|
60
|
-
knxMsgPayload.rawEvent = _event
|
|
61
|
-
node.send(knxMsgPayload)
|
|
62
|
-
node.setNodeStatusHue({
|
|
69
|
+
knxMsgPayload.rawEvent = _event;
|
|
70
|
+
node.send(knxMsgPayload);
|
|
71
|
+
node.setNodeStatusHue({
|
|
72
|
+
fill: "blue",
|
|
73
|
+
shape: "ring",
|
|
74
|
+
text: "HUE->KNX",
|
|
75
|
+
payload: knxMsgPayload.payload,
|
|
76
|
+
});
|
|
63
77
|
}
|
|
64
78
|
}
|
|
65
79
|
} catch (error) {
|
|
66
|
-
node.status({ fill:
|
|
80
|
+
node.status({ fill: "red", shape: "dot", text: `HUE->KNX error ${error.message} (${new Date().getDate()}, ${new Date().toLocaleTimeString()})` });
|
|
67
81
|
}
|
|
68
|
-
}
|
|
82
|
+
};
|
|
69
83
|
|
|
70
84
|
// On each deploy, unsubscribe+resubscribe
|
|
71
85
|
if (node.server) {
|
|
72
|
-
node.server.removeClient(node)
|
|
73
|
-
node.server.addClient(node)
|
|
86
|
+
node.server.removeClient(node);
|
|
87
|
+
node.server.addClient(node);
|
|
74
88
|
}
|
|
75
89
|
if (node.serverHue) {
|
|
76
|
-
node.serverHue.removeClient(node)
|
|
77
|
-
node.serverHue.addClient(node)
|
|
90
|
+
node.serverHue.removeClient(node);
|
|
91
|
+
node.serverHue.addClient(node);
|
|
78
92
|
}
|
|
79
93
|
|
|
80
|
-
node.on(
|
|
81
|
-
|
|
82
|
-
})
|
|
94
|
+
node.on("input", (msg) => {});
|
|
83
95
|
|
|
84
|
-
node.on(
|
|
96
|
+
node.on("close", (done) => {
|
|
85
97
|
if (node.server) {
|
|
86
|
-
node.server.removeClient(node)
|
|
98
|
+
node.server.removeClient(node);
|
|
87
99
|
}
|
|
88
100
|
if (node.serverHue) {
|
|
89
|
-
node.serverHue.removeClient(node)
|
|
101
|
+
node.serverHue.removeClient(node);
|
|
90
102
|
}
|
|
91
|
-
done()
|
|
92
|
-
})
|
|
103
|
+
done();
|
|
104
|
+
});
|
|
93
105
|
}
|
|
94
|
-
RED.nodes.registerType(
|
|
95
|
-
}
|
|
106
|
+
RED.nodes.registerType("knxUltimateHueMotion", knxUltimateHueMotion);
|
|
107
|
+
};
|
|
@@ -82,7 +82,7 @@ module.exports = function (RED) {
|
|
|
82
82
|
// knxMsgPayload.dpt = config.dptmotion
|
|
83
83
|
|
|
84
84
|
// if (_event.hasOwnProperty('motion') && _event.motion.hasOwnProperty('motion')) {
|
|
85
|
-
// knxMsgPayload.payload = _event.motion.motion
|
|
85
|
+
// knxMsgPayload.payload = _event.motion.motion_report.motion
|
|
86
86
|
// // Send to KNX bus
|
|
87
87
|
// if (knxMsgPayload.topic !== '' && knxMsgPayload.topic !== undefined) node.server.writeQueueAdd({ grpaddr: knxMsgPayload.topic, payload: knxMsgPayload.payload, dpt: knxMsgPayload.dpt, outputtype: 'write', nodecallerid: node.id })
|
|
88
88
|
// node.status({ fill: 'green', shape: 'dot', text: 'HUE->KNX ' + JSON.stringify(knxMsgPayload.payload) + ' (' + new Date().getDate() + ', ' + new Date().toLocaleTimeString() + ')' })
|
|
@@ -1,108 +1,107 @@
|
|
|
1
1
|
module.exports = function (RED) {
|
|
2
|
-
function knxUltimateHueTemperatureSensor
|
|
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
|
|
2
|
+
function knxUltimateHueTemperatureSensor(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;
|
|
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
|
-
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
node.setNodeStatusHue = ({
|
|
34
|
+
fill, shape, text, payload,
|
|
35
|
+
}) => {
|
|
36
|
+
if (payload === undefined) return;
|
|
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.GAtemperaturesensor
|
|
47
|
-
knxMsgPayload.dpt = config.dpttemperaturesensor
|
|
49
|
+
const knxMsgPayload = {};
|
|
50
|
+
knxMsgPayload.topic = config.GAtemperaturesensor;
|
|
51
|
+
knxMsgPayload.dpt = config.dpttemperaturesensor;
|
|
48
52
|
|
|
49
53
|
if (_event.hasOwnProperty('temperature') && _event.temperature.hasOwnProperty('temperature')) {
|
|
50
|
-
knxMsgPayload.payload = _event.temperature.temperature
|
|
54
|
+
knxMsgPayload.payload = _event.temperature.temperature;
|
|
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
|
+
node.status({ fill: 'green', shape: 'dot', text: `HUE->KNX ${JSON.stringify(knxMsgPayload.payload)} (${new Date().getDate()}, ${new Date().toLocaleTimeString()})` });
|
|
54
62
|
|
|
55
63
|
// Setup the output msg
|
|
56
|
-
knxMsgPayload.name = node.name
|
|
57
|
-
knxMsgPayload.event = 'temperature'
|
|
64
|
+
knxMsgPayload.name = node.name;
|
|
65
|
+
knxMsgPayload.event = 'temperature';
|
|
58
66
|
|
|
59
67
|
// Send payload
|
|
60
|
-
knxMsgPayload.rawEvent = _event
|
|
61
|
-
node.send(knxMsgPayload)
|
|
62
|
-
node.setNodeStatusHue({
|
|
68
|
+
knxMsgPayload.rawEvent = _event;
|
|
69
|
+
node.send(knxMsgPayload);
|
|
70
|
+
node.setNodeStatusHue({
|
|
71
|
+
fill: 'blue', shape: 'ring', text: 'HUE->KNX', payload: knxMsgPayload.payload,
|
|
72
|
+
});
|
|
63
73
|
}
|
|
64
74
|
}
|
|
65
75
|
} catch (error) {
|
|
66
|
-
node.status({ fill: 'red', shape: 'dot', text:
|
|
76
|
+
node.status({ fill: 'red', shape: 'dot', text: `HUE->KNX error ${error.message} (${new Date().getDate()}, ${new Date().toLocaleTimeString()})` });
|
|
67
77
|
}
|
|
68
|
-
}
|
|
78
|
+
};
|
|
69
79
|
|
|
70
80
|
// On each deploy, unsubscribe+resubscribe
|
|
71
81
|
if (node.server) {
|
|
72
|
-
node.server.removeClient(node)
|
|
73
|
-
node.server.addClient(node)
|
|
82
|
+
node.server.removeClient(node);
|
|
83
|
+
node.server.addClient(node);
|
|
74
84
|
}
|
|
75
85
|
if (node.serverHue) {
|
|
76
|
-
node.serverHue.removeClient(node)
|
|
77
|
-
// I must get the object, to store read the battery status
|
|
78
|
-
// I queue the state request, by passing the callback to call whenever the HUE bridge send me the light status async
|
|
86
|
+
node.serverHue.removeClient(node);
|
|
79
87
|
if (node.serverHue !== null && node.serverHue.hueManager !== null) {
|
|
80
|
-
(
|
|
81
|
-
try {
|
|
82
|
-
node.serverHue.addClient(node)
|
|
83
|
-
await node.serverHue.hueManager.writeHueQueueAdd(config.hueDevice, null, 'getTemperature', (jLight) => {
|
|
84
|
-
node.handleSendHUE(jLight)
|
|
85
|
-
})
|
|
86
|
-
} catch (err) {
|
|
87
|
-
RED.log.error('Errore knxUltimateHueLight node.currentHUEDevice ' + err.message)
|
|
88
|
-
}
|
|
89
|
-
})()
|
|
88
|
+
node.serverHue.addClient(node);
|
|
90
89
|
}
|
|
91
90
|
}
|
|
92
91
|
|
|
93
|
-
node.on('input',
|
|
92
|
+
node.on('input', (msg) => {
|
|
94
93
|
|
|
95
|
-
})
|
|
94
|
+
});
|
|
96
95
|
|
|
97
|
-
node.on('close',
|
|
96
|
+
node.on('close', (done) => {
|
|
98
97
|
if (node.server) {
|
|
99
|
-
node.server.removeClient(node)
|
|
98
|
+
node.server.removeClient(node);
|
|
100
99
|
}
|
|
101
100
|
if (node.serverHue) {
|
|
102
|
-
node.serverHue.removeClient(node)
|
|
101
|
+
node.serverHue.removeClient(node);
|
|
103
102
|
}
|
|
104
|
-
done()
|
|
105
|
-
})
|
|
103
|
+
done();
|
|
104
|
+
});
|
|
106
105
|
}
|
|
107
|
-
RED.nodes.registerType('knxUltimateHueTemperatureSensor', knxUltimateHueTemperatureSensor)
|
|
108
|
-
}
|
|
106
|
+
RED.nodes.registerType('knxUltimateHueTemperatureSensor', knxUltimateHueTemperatureSensor);
|
|
107
|
+
};
|
|
@@ -80,4 +80,32 @@
|
|
|
80
80
|
|
|
81
81
|
|
|
82
82
|
|
|
83
|
+
</script>
|
|
84
|
+
|
|
85
|
+
<script type="text/markdown" data-help-name="knxUltimateViewer">
|
|
86
|
+
View all group addresses and their values in a Dashboard widget.
|
|
87
|
+
|
|
88
|
+
This node works in conjunction with the Node-Red dashboard UI Template node.
|
|
89
|
+
View all group addresses and their values in a Dashboard widget.
|
|
90
|
+
|
|
91
|
+
**General**
|
|
92
|
+
|Property|Description|
|
|
93
|
+
|--|--|
|
|
94
|
+
| KNX Gateway | The Gateway you wish to connect to. |
|
|
95
|
+
| Name | The node name |
|
|
96
|
+
|
|
|
97
|
+
<br/>
|
|
98
|
+
|
|
99
|
+
### Outputs
|
|
100
|
+
|
|
101
|
+
1. Standard output
|
|
102
|
+
: payload (json) : formatted payload. Connect it directly with the Template UI node.
|
|
103
|
+
2. Array of objects
|
|
104
|
+
: payload (array) : An array containing all the GA. You can use the array to do your own format and reordering.
|
|
105
|
+
|
|
106
|
+
<br/>
|
|
107
|
+
|
|
108
|
+
[Find it useful?](https://www.paypal.me/techtoday)
|
|
109
|
+
|
|
110
|
+
<br/>
|
|
83
111
|
</script>
|
package/nodes/utils/hueEngine.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/* eslint-disable max-len */
|
|
2
|
-
const { EventEmitter } = require(
|
|
3
|
-
const EventSource = require(
|
|
4
|
-
const http = require(
|
|
2
|
+
const { EventEmitter } = require("events");
|
|
3
|
+
const EventSource = require("eventsource");
|
|
4
|
+
const http = require("./http");
|
|
5
5
|
|
|
6
6
|
class classHUE extends EventEmitter {
|
|
7
7
|
constructor(_hueBridgeIP, _username, _clientkey, _bridgeid, _sysLogger) {
|
|
@@ -20,7 +20,9 @@ class classHUE extends EventEmitter {
|
|
|
20
20
|
Connect = async () => {
|
|
21
21
|
const options = {
|
|
22
22
|
headers: {
|
|
23
|
-
|
|
23
|
+
"hue-application-key": this.username,
|
|
24
|
+
pragma: "no-cache",
|
|
25
|
+
"cache-control": "no-cache,no-store, must-revalidate",
|
|
24
26
|
},
|
|
25
27
|
https: {
|
|
26
28
|
rejectUnauthorized: false,
|
|
@@ -36,29 +38,32 @@ class classHUE extends EventEmitter {
|
|
|
36
38
|
try {
|
|
37
39
|
this.es.close();
|
|
38
40
|
this.es = null;
|
|
39
|
-
} catch (error) {
|
|
41
|
+
} catch (error) {
|
|
42
|
+
/* empty */
|
|
43
|
+
}
|
|
40
44
|
this.es = new EventSource(`https://${this.hueBridgeIP}/eventstream/clip/v2`, options);
|
|
41
45
|
|
|
42
46
|
this.es.onmessage = (event) => {
|
|
43
47
|
try {
|
|
44
|
-
if (event && event.type ===
|
|
48
|
+
if (event && event.type === "message" && event.data) {
|
|
45
49
|
const data = JSON.parse(event.data);
|
|
46
50
|
data.forEach((element) => {
|
|
47
|
-
if (element.type ===
|
|
51
|
+
if (element.type === "update") {
|
|
48
52
|
element.data.forEach((ev) => {
|
|
49
|
-
this.emit(
|
|
53
|
+
this.emit("event", ev);
|
|
50
54
|
});
|
|
51
55
|
}
|
|
52
56
|
});
|
|
53
57
|
}
|
|
54
58
|
} catch (error) {
|
|
55
|
-
if (this.sysLogger !== undefined && this.sysLogger !== null)
|
|
59
|
+
if (this.sysLogger !== undefined && this.sysLogger !== null)
|
|
60
|
+
this.sysLogger.error(`KNXUltimatehueEngine: classHUE: this.es.onmessage: ${error.message}`);
|
|
56
61
|
}
|
|
57
62
|
};
|
|
58
63
|
|
|
59
64
|
this.es.onopen = () => {
|
|
60
65
|
// if (this.sysLogger !== undefined && this.sysLogger !== null) this.sysLogger.error('KNXUltimatehueEngine: classHUE: SSE-Connected')
|
|
61
|
-
this.emit(
|
|
66
|
+
this.emit("connected");
|
|
62
67
|
};
|
|
63
68
|
|
|
64
69
|
// this.es.onerror = (error) => {
|
|
@@ -78,7 +83,9 @@ class classHUE extends EventEmitter {
|
|
|
78
83
|
try {
|
|
79
84
|
this.es.close();
|
|
80
85
|
this.es = null;
|
|
81
|
-
} catch (error) {
|
|
86
|
+
} catch (error) {
|
|
87
|
+
/* empty */
|
|
88
|
+
}
|
|
82
89
|
this.Connect();
|
|
83
90
|
}, 300000);
|
|
84
91
|
};
|
|
@@ -91,61 +98,68 @@ class classHUE extends EventEmitter {
|
|
|
91
98
|
const jRet = this.commandQueue.shift();
|
|
92
99
|
// jRet is ({ _lightID, _state, _operation });;
|
|
93
100
|
switch (jRet._operation) {
|
|
94
|
-
case
|
|
101
|
+
case "setLight":
|
|
95
102
|
// It can be a light or a grouped light
|
|
96
103
|
try {
|
|
97
104
|
const ok = await this.hueApiV2.put(`/resource/light/${jRet._lightID}`, jRet._state);
|
|
98
105
|
} catch (error) {
|
|
99
|
-
if (this.sysLogger !== undefined && this.sysLogger !== null)
|
|
106
|
+
if (this.sysLogger !== undefined && this.sysLogger !== null)
|
|
107
|
+
this.sysLogger.info(`KNXUltimatehueEngine: classHUE: handleQueue: setLight light: ${error.message}`);
|
|
100
108
|
}
|
|
101
109
|
break;
|
|
102
|
-
case
|
|
110
|
+
case "setGroupedLight":
|
|
103
111
|
try {
|
|
104
112
|
await this.hueApiV2.put(`/resource/grouped_light/${jRet._lightID}`, jRet._state);
|
|
105
113
|
} catch (error) {
|
|
106
|
-
if (this.sysLogger !== undefined && this.sysLogger !== null)
|
|
114
|
+
if (this.sysLogger !== undefined && this.sysLogger !== null)
|
|
115
|
+
this.sysLogger.info(`KNXUltimatehueEngine: classHUE: handleQueue: setLight grouped_light: ${error.message}`);
|
|
107
116
|
}
|
|
108
117
|
break;
|
|
109
|
-
case
|
|
118
|
+
case "setScene":
|
|
110
119
|
try {
|
|
111
120
|
const sceneID = jRet._lightID;
|
|
112
121
|
await this.hueApiV2.put(`/resource/scene/${sceneID}`, jRet._state);
|
|
113
122
|
} catch (error) {
|
|
114
|
-
if (this.sysLogger !== undefined && this.sysLogger !== null)
|
|
123
|
+
if (this.sysLogger !== undefined && this.sysLogger !== null)
|
|
124
|
+
this.sysLogger.info(`KNXUltimatehueEngine: classHUE: handleQueue: setScene: ${error.message}`);
|
|
115
125
|
}
|
|
116
126
|
break;
|
|
117
|
-
case
|
|
127
|
+
case "stopScene":
|
|
118
128
|
try {
|
|
119
|
-
const allResources = await this.hueApiV2.get(
|
|
129
|
+
const allResources = await this.hueApiV2.get("/resource");
|
|
120
130
|
const sceneID = jRet._lightID;
|
|
121
|
-
const jScene = allResources.find((res) => res.id === sceneID) ||
|
|
122
|
-
const linkedLight = allResources.find((res) => res.id === jScene.group.rid).children ||
|
|
131
|
+
const jScene = allResources.find((res) => res.id === sceneID) || "";
|
|
132
|
+
const linkedLight = allResources.find((res) => res.id === jScene.group.rid).children || "";
|
|
123
133
|
linkedLight.forEach((light) => {
|
|
124
|
-
this.writeHueQueueAdd(light.rid, jRet._state,
|
|
134
|
+
this.writeHueQueueAdd(light.rid, jRet._state, "setLight");
|
|
125
135
|
});
|
|
126
136
|
} catch (error) {
|
|
127
|
-
if (this.sysLogger !== undefined && this.sysLogger !== null)
|
|
137
|
+
if (this.sysLogger !== undefined && this.sysLogger !== null)
|
|
138
|
+
this.sysLogger.error(`KNXUltimatehueEngine: classHUE: handleQueue: stopScene: ${error.message}`);
|
|
128
139
|
}
|
|
129
140
|
break;
|
|
130
|
-
case
|
|
141
|
+
case "getBattery":
|
|
131
142
|
try {
|
|
132
143
|
const jReturn = await this.hueApiV2.get(`/resource/device_power/${jRet._lightID}`);
|
|
133
144
|
} catch (error) {
|
|
134
|
-
if (this.sysLogger !== undefined && this.sysLogger !== null)
|
|
145
|
+
if (this.sysLogger !== undefined && this.sysLogger !== null)
|
|
146
|
+
this.sysLogger.error(`KNXUltimatehueEngine: classHUE: handleQueue: getBattery: ${error.message}`);
|
|
135
147
|
}
|
|
136
148
|
break;
|
|
137
|
-
case
|
|
149
|
+
case "getLightLevel":
|
|
138
150
|
try {
|
|
139
151
|
const jReturn = await this.hueApiV2.get(`/resource/light_level/${jRet._lightID}`);
|
|
140
152
|
} catch (error) {
|
|
141
|
-
if (this.sysLogger !== undefined && this.sysLogger !== null)
|
|
153
|
+
if (this.sysLogger !== undefined && this.sysLogger !== null)
|
|
154
|
+
this.sysLogger.error(`KNXUltimatehueEngine: classHUE: handleQueue: getLightLevel: ${error.message}`);
|
|
142
155
|
}
|
|
143
156
|
break;
|
|
144
|
-
case
|
|
157
|
+
case "getTemperature":
|
|
145
158
|
try {
|
|
146
159
|
const jReturn = await this.hueApiV2.get(`/resource/temperature/${jRet._lightID}`);
|
|
147
160
|
} catch (error) {
|
|
148
|
-
if (this.sysLogger !== undefined && this.sysLogger !== null)
|
|
161
|
+
if (this.sysLogger !== undefined && this.sysLogger !== null)
|
|
162
|
+
this.sysLogger.error(`KNXUltimatehueEngine: classHUE: handleQueue: getTemperature: ${error.message}`);
|
|
149
163
|
}
|
|
150
164
|
break;
|
|
151
165
|
default:
|
|
@@ -162,18 +176,19 @@ class classHUE extends EventEmitter {
|
|
|
162
176
|
};
|
|
163
177
|
// ######################################
|
|
164
178
|
|
|
165
|
-
close = async () =>
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
179
|
+
close = async () =>
|
|
180
|
+
new Promise((resolve, reject) => {
|
|
181
|
+
try {
|
|
182
|
+
if (this.timerReconnect !== undefined) clearInterval(this.timerReconnect);
|
|
183
|
+
this.closePushEventStream = true;
|
|
184
|
+
if (this.es !== null) this.es.close();
|
|
185
|
+
this.es = null;
|
|
186
|
+
setTimeout(() => {
|
|
187
|
+
resolve(true);
|
|
188
|
+
}, 500);
|
|
189
|
+
} catch (error) {
|
|
190
|
+
reject(error);
|
|
191
|
+
}
|
|
192
|
+
});
|
|
178
193
|
}
|
|
179
194
|
module.exports.classHUE = classHUE;
|
package/package.json
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
"engines": {
|
|
4
4
|
"node": ">=16.0.0"
|
|
5
5
|
},
|
|
6
|
-
"version": "2.2.
|
|
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
|
|
6
|
+
"version": "2.2.3",
|
|
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",
|
|
10
10
|
"color-convert": "2.0.1",
|
|
@@ -52,8 +52,6 @@
|
|
|
52
52
|
"KNX",
|
|
53
53
|
"ETS",
|
|
54
54
|
"eib",
|
|
55
|
-
"eibd",
|
|
56
|
-
"knxd",
|
|
57
55
|
"konnex",
|
|
58
56
|
"IOT",
|
|
59
57
|
"hue"
|
|
@@ -69,5 +67,28 @@
|
|
|
69
67
|
},
|
|
70
68
|
"scripts": {
|
|
71
69
|
"test": "standard"
|
|
70
|
+
},
|
|
71
|
+
"Prettier": {
|
|
72
|
+
"arrowParens": "always",
|
|
73
|
+
"bracketSameLine": true,
|
|
74
|
+
"bracketSpacing": false,
|
|
75
|
+
"semi": true,
|
|
76
|
+
"singleQuote": true,
|
|
77
|
+
"jsxSingleQuote": false,
|
|
78
|
+
"quoteProps": "as-needed",
|
|
79
|
+
"trailingComma": "all",
|
|
80
|
+
"singleAttributePerLine": false,
|
|
81
|
+
"htmlWhitespaceSensitivity": "css",
|
|
82
|
+
"vueIndentScriptAndStyle": false,
|
|
83
|
+
"proseWrap": "preserve",
|
|
84
|
+
"insertPragma": false,
|
|
85
|
+
"printWidth": 80,
|
|
86
|
+
"requirePragma": false,
|
|
87
|
+
"tabWidth": 2,
|
|
88
|
+
"useTabs": true,
|
|
89
|
+
"embeddedLanguageFormatting": "auto",
|
|
90
|
+
"[html]": {
|
|
91
|
+
"editor.defaultFormatter": "vscode.html-language-features"
|
|
92
|
+
}
|
|
72
93
|
}
|
|
73
94
|
}
|