node-red-contrib-knx-ultimate 2.0.1 → 2.0.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 +5 -0
- package/README.md +1 -1
- package/img/hueButton.png +0 -0
- package/img/hueLight.png +0 -0
- package/nodes/hue-config.js +20 -2
- package/nodes/knxUltimateHueButton.html +586 -0
- package/nodes/knxUltimateHueButton.js +159 -0
- package/nodes/knxUltimateHueLight.html +78 -35
- package/nodes/knxUltimateHueLight.js +16 -14
- package/nodes/utils/hueUtils.js +26 -21
- package/package.json +4 -3
- package/nodes/locales/en-US/knxUltimateHueLight.html +0 -10
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,11 @@
|
|
|
6
6
|
|
|
7
7
|
# CHANGELOG
|
|
8
8
|
|
|
9
|
+
<p>
|
|
10
|
+
<b>Version 2.0.2</b> - June 2023<br/>
|
|
11
|
+
- NEW: HUE Button node. All HUE integrations are in BETA.<br/>
|
|
12
|
+
- Slowly integrating the help in the node-red help section.<br/>
|
|
13
|
+
</p>
|
|
9
14
|
<p>
|
|
10
15
|
<b>Version 2.0.1</b> - June 2023<br/>
|
|
11
16
|
- NEW: more KNX group addresses in the HUE Light node<br/>
|
package/README.md
CHANGED
|
@@ -35,7 +35,7 @@ msg.payload = {red:255, green:200, blue:30} // Put some colors in our life
|
|
|
35
35
|
* **ALERTER node** [here](https://github.com/Supergiovane/node-red-contrib-knx-ultimate/wiki/Alerter-Configuration). With the Alerter node you can signal to a display or to the node-red-contrib-tts-ultimate node (audio feedback), whenever the selected devices are alerted, i.e. they have payload **true**.
|
|
36
36
|
* **LOAD CONTROL node** [here](https://github.com/Supergiovane/node-red-contrib-knx-ultimate/wiki/LoadControl-Configuration). Control your loads (Oven, Washing machine, etc..) and avoit shutting down the main voltage due to too high power consumption.
|
|
37
37
|
* **VIEWER node** [here](https://github.com/Supergiovane/node-red-contrib-knx-ultimate/wiki/knxUltimateViewer). View all Group Addresses and values of your KNX BUS, in the Node-Red Dashboard.
|
|
38
|
-
* **PHILIPS HUE nodeset** [here](https://github.com/Supergiovane/node-red-contrib-knx-ultimate/wiki/en-hue-configuration). Link HUE
|
|
38
|
+
* **PHILIPS HUE nodeset** [here](https://github.com/Supergiovane/node-red-contrib-knx-ultimate/wiki/en-hue-configuration). Link HUE devices to KNX in a simple way.
|
|
39
39
|
|
|
40
40
|
<br>
|
|
41
41
|
<br>
|
|
Binary file
|
package/img/hueLight.png
ADDED
|
Binary file
|
package/nodes/hue-config.js
CHANGED
|
@@ -90,7 +90,7 @@ module.exports = (RED) => {
|
|
|
90
90
|
})
|
|
91
91
|
})
|
|
92
92
|
|
|
93
|
-
// Endpoint
|
|
93
|
+
// Endpoint frontend
|
|
94
94
|
RED.httpAdmin.get('/KNXUltimateGetAllLightsHUE', RED.auth.needsPermission('hue-config.read'), function (req, res) {
|
|
95
95
|
try {
|
|
96
96
|
(async () => {
|
|
@@ -110,7 +110,25 @@ module.exports = (RED) => {
|
|
|
110
110
|
}
|
|
111
111
|
})
|
|
112
112
|
|
|
113
|
-
|
|
113
|
+
RED.httpAdmin.get('/KNXUltimateGetDevicesHUE', RED.auth.needsPermission('hue-config.read'), function (req, res) {
|
|
114
|
+
try {
|
|
115
|
+
(async () => {
|
|
116
|
+
try {
|
|
117
|
+
// °°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°
|
|
118
|
+
const jRet = await node.hueManager.getDevices(req.query.rtype)
|
|
119
|
+
res.json(jRet)
|
|
120
|
+
// °°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°
|
|
121
|
+
} catch (err) {
|
|
122
|
+
RED.log.error('Errore KNXUltimategetButtonsHUE non gestito ' + err.message)
|
|
123
|
+
res.json({ error: err.message })
|
|
124
|
+
}
|
|
125
|
+
})()
|
|
126
|
+
} catch (err) {
|
|
127
|
+
RED.log.error('Errore KNXUltimategetButtons bsonto ' + err.message)
|
|
128
|
+
res.json({ error: err.message })
|
|
129
|
+
}
|
|
130
|
+
})
|
|
131
|
+
|
|
114
132
|
node.addClient = (_Node) => {
|
|
115
133
|
// Check if node already exists
|
|
116
134
|
if (node.nodeClients.filter(x => x.id === _Node.id).length === 0) {
|
|
@@ -0,0 +1,586 @@
|
|
|
1
|
+
<script type="text/javascript">
|
|
2
|
+
RED.nodes.registerType('knxUltimateHueButton', {
|
|
3
|
+
category: "KNX Ultimate",
|
|
4
|
+
color: '#C7E9C0',
|
|
5
|
+
defaults: {
|
|
6
|
+
//buttonState: {value: true},
|
|
7
|
+
server: { type: "knxUltimate-config", required: true },
|
|
8
|
+
serverHue: { type: "hue-config", required: true },
|
|
9
|
+
name: { value: "Hue Button (beta)" },
|
|
10
|
+
|
|
11
|
+
nameinitial_press: { value: "" },
|
|
12
|
+
GAinitial_press: { value: "" },
|
|
13
|
+
dptinitial_press: { value: "" },
|
|
14
|
+
|
|
15
|
+
namerepeat: { value: "" },
|
|
16
|
+
GArepeat: { value: "" },
|
|
17
|
+
dptrepeat: { value: "" },
|
|
18
|
+
|
|
19
|
+
nameshort_release: { value: "" },
|
|
20
|
+
GAshort_release: { value: "" },
|
|
21
|
+
dptshort_release: { value: "" },
|
|
22
|
+
|
|
23
|
+
namelong_release: { value: "" },
|
|
24
|
+
GAlong_release: { value: "" },
|
|
25
|
+
dptlong_release: { value: "" },
|
|
26
|
+
|
|
27
|
+
namedouble_short_release: { value: "" },
|
|
28
|
+
GAdouble_short_release: { value: "" },
|
|
29
|
+
dptdouble_short_release: { value: "" },
|
|
30
|
+
|
|
31
|
+
namelong_press: { value: "" },
|
|
32
|
+
GAlong_press: { value: "" },
|
|
33
|
+
dptlong_press: { value: "" },
|
|
34
|
+
|
|
35
|
+
toggleValues: { value: true },
|
|
36
|
+
hueDevice: { value: "" }
|
|
37
|
+
},
|
|
38
|
+
inputs: 0,
|
|
39
|
+
outputs: 0,
|
|
40
|
+
icon: "node-hue-icon.svg",
|
|
41
|
+
label: function () {
|
|
42
|
+
return (this.name);
|
|
43
|
+
},
|
|
44
|
+
paletteLabel: "Hue Button",
|
|
45
|
+
// button: {
|
|
46
|
+
// enabled: function() {
|
|
47
|
+
// // return whether or not the button is enabled, based on the current
|
|
48
|
+
// // configuration of the node
|
|
49
|
+
// return !this.changed
|
|
50
|
+
// },
|
|
51
|
+
// visible: function() {
|
|
52
|
+
// // return whether or not the button is visible, based on the current
|
|
53
|
+
// // configuration of the node
|
|
54
|
+
// return this.hasButton
|
|
55
|
+
// },
|
|
56
|
+
// //toggle: "buttonState",
|
|
57
|
+
// onclick: function() {}
|
|
58
|
+
// },
|
|
59
|
+
oneditprepare: function () {
|
|
60
|
+
var node = this;
|
|
61
|
+
var oNodeServer = RED.nodes.node($("#node-input-server").val()); // Store the config-node
|
|
62
|
+
var oNodeServerHue = RED.nodes.node($("#node-input-serverHue").val()); // Store the config-node
|
|
63
|
+
|
|
64
|
+
// 19/02/2020 Used to get the server sooner als deploy.
|
|
65
|
+
$("#node-input-server").change(function () {
|
|
66
|
+
try {
|
|
67
|
+
oNodeServer = RED.nodes.node($(this).val());
|
|
68
|
+
} catch (error) { }
|
|
69
|
+
});
|
|
70
|
+
// 19/02/2020 Used to get the server sooner als deploy.
|
|
71
|
+
$("#node-input-serverHue").change(function () {
|
|
72
|
+
try {
|
|
73
|
+
oNodeServerHue = RED.nodes.node($(this).val());
|
|
74
|
+
} catch (error) { }
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// 31/03/2020 Search Helper
|
|
78
|
+
function fullSearch(sourceText, searchString) {
|
|
79
|
+
// This searches for all words in a string
|
|
80
|
+
var aSearchWords = searchString.toLowerCase().split(" ");
|
|
81
|
+
var i = 0;
|
|
82
|
+
for (let index = 0; index < aSearchWords.length; index++) {
|
|
83
|
+
if (sourceText.toLowerCase().indexOf(aSearchWords[index]) > -1) i += 1;
|
|
84
|
+
}
|
|
85
|
+
return i == aSearchWords.length;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// DPT Switch command
|
|
89
|
+
// ########################
|
|
90
|
+
$.getJSON('knxUltimateDpts', (data) => {
|
|
91
|
+
data.forEach(dpt => {
|
|
92
|
+
if (dpt.value.startsWith("1.")) {
|
|
93
|
+
$("#node-input-dptinitial_press").append($("<option></option>")
|
|
94
|
+
.attr("value", dpt.value)
|
|
95
|
+
.text(dpt.text))
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
$("#node-input-dptinitial_press").val(this.dptinitial_press)
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
// Autocomplete suggestion with ETS csv File
|
|
102
|
+
$("#node-input-GAinitial_press").autocomplete({
|
|
103
|
+
minLength: 1,
|
|
104
|
+
source: function (request, response) {
|
|
105
|
+
//$.getJSON("csv", request, function( data, status, xhr ) {
|
|
106
|
+
$.getJSON("knxUltimatecsv?nodeID=" + oNodeServer.id, (data) => {
|
|
107
|
+
response($.map(data, function (value, key) {
|
|
108
|
+
var sSearch = (value.ga + " (" + value.devicename + ") DPT" + value.dpt);
|
|
109
|
+
if (fullSearch(sSearch, request.term + " 1.")) {
|
|
110
|
+
return {
|
|
111
|
+
label: value.ga + " # " + value.devicename + " # " + value.dpt, // Label for Display
|
|
112
|
+
value: value.ga // Value
|
|
113
|
+
}
|
|
114
|
+
} else {
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
}));
|
|
118
|
+
});
|
|
119
|
+
}, select: function (event, ui) {
|
|
120
|
+
// Sets Datapoint and device name automatically
|
|
121
|
+
var sDevName = ui.item.label.split("#")[1].trim();
|
|
122
|
+
try {
|
|
123
|
+
sDevName = sDevName.substr(sDevName.indexOf(")") + 1).trim();
|
|
124
|
+
} catch (error) {
|
|
125
|
+
}
|
|
126
|
+
$('#node-input-nameinitial_press').val(sDevName);
|
|
127
|
+
var optVal = $("#node-input-dptinitial_press option:contains('" + ui.item.label.split("#")[2].trim() + "')").attr('value');
|
|
128
|
+
// Select the option value
|
|
129
|
+
$("#node-input-dptinitial_press").val(optVal);
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
// ########################
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
// DPT repeat
|
|
137
|
+
// ########################
|
|
138
|
+
$.getJSON('knxUltimateDpts', (data) => {
|
|
139
|
+
data.forEach(dpt => {
|
|
140
|
+
if (dpt.value.startsWith("1.") || dpt.value.startsWith("3.007")) {
|
|
141
|
+
$("#node-input-dptrepeat").append($("<option></option>")
|
|
142
|
+
.attr("value", dpt.value)
|
|
143
|
+
.text(dpt.text))
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
$("#node-input-dptrepeat").val(this.dptrepeat)
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
// Autocomplete suggestion with ETS csv File
|
|
151
|
+
$("#node-input-GArepeat").autocomplete({
|
|
152
|
+
minLength: 1,
|
|
153
|
+
source: function (request, response) {
|
|
154
|
+
$.getJSON("knxUltimatecsv?nodeID=" + oNodeServer.id, (data) => {
|
|
155
|
+
response($.map(data, function (value, key) {
|
|
156
|
+
var sSearch = (value.ga + " (" + value.devicename + ") DPT" + value.dpt);
|
|
157
|
+
if (fullSearch(sSearch, request.term)) {
|
|
158
|
+
if (value.dpt.startsWith('1.') || value.dpt.startsWith('3.007')) {
|
|
159
|
+
return {
|
|
160
|
+
label: value.ga + " # " + value.devicename + " # " + value.dpt, // Label for Display
|
|
161
|
+
value: value.ga // Value
|
|
162
|
+
}
|
|
163
|
+
} else { return null; }
|
|
164
|
+
} else {
|
|
165
|
+
return null;
|
|
166
|
+
}
|
|
167
|
+
}));
|
|
168
|
+
});
|
|
169
|
+
}, select: function (event, ui) {
|
|
170
|
+
// Sets Datapoint and device name automatically
|
|
171
|
+
var sDevName = ui.item.label.split("#")[1].trim();
|
|
172
|
+
try {
|
|
173
|
+
sDevName = sDevName.substr(sDevName.indexOf(")") + 1).trim();
|
|
174
|
+
} catch (error) {
|
|
175
|
+
}
|
|
176
|
+
$('#node-input-namerepeat').val(sDevName);
|
|
177
|
+
var optVal = $("#node-input-dptrepeat option:contains('" + ui.item.label.split("#")[2].trim() + "')").attr('value');
|
|
178
|
+
// Select the option value
|
|
179
|
+
$("#node-input-dptrepeat").val(optVal);
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
// DPT dptshort_release
|
|
185
|
+
// ########################
|
|
186
|
+
$.getJSON('knxUltimateDpts', (data) => {
|
|
187
|
+
data.forEach(dpt => {
|
|
188
|
+
if (dpt.value.startsWith('1.')) {
|
|
189
|
+
$("#node-input-dptshort_release").append($("<option></option>")
|
|
190
|
+
.attr("value", dpt.value)
|
|
191
|
+
.text(dpt.text))
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
$("#node-input-dptshort_release").val(this.dptshort_release)
|
|
196
|
+
|
|
197
|
+
})
|
|
198
|
+
|
|
199
|
+
// Autocomplete suggestion with ETS csv File
|
|
200
|
+
$("#node-input-GAshort_release").autocomplete({
|
|
201
|
+
minLength: 1,
|
|
202
|
+
source: function (request, response) {
|
|
203
|
+
$.getJSON("knxUltimatecsv?nodeID=" + oNodeServer.id, (data) => {
|
|
204
|
+
response($.map(data, function (value, key) {
|
|
205
|
+
var sSearch = (value.ga + " (" + value.devicename + ") DPT" + value.dpt);
|
|
206
|
+
if (fullSearch(sSearch, request.term + " 1.")) {
|
|
207
|
+
return {
|
|
208
|
+
label: value.ga + " # " + value.devicename + " # " + value.dpt, // Label for Display
|
|
209
|
+
value: value.ga // Value
|
|
210
|
+
}
|
|
211
|
+
} else {
|
|
212
|
+
return null;
|
|
213
|
+
}
|
|
214
|
+
}));
|
|
215
|
+
});
|
|
216
|
+
}, select: function (event, ui) {
|
|
217
|
+
// Sets Datapoint and device name automatically
|
|
218
|
+
var sDevName = ui.item.label.split("#")[1].trim();
|
|
219
|
+
try {
|
|
220
|
+
sDevName = sDevName.substr(sDevName.indexOf(")") + 1).trim();
|
|
221
|
+
} catch (error) {
|
|
222
|
+
}
|
|
223
|
+
$('#node-input-nameshort_release').val(sDevName);
|
|
224
|
+
var optVal = $("#node-input-dptshort_release option:contains('" + ui.item.label.split("#")[2].trim() + "')").attr('value');
|
|
225
|
+
// Select the option value
|
|
226
|
+
$("#node-input-dptshort_release").val(optVal);
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
// DPT dptlong_release and dptLightColorStateƒ
|
|
232
|
+
// ########################
|
|
233
|
+
$.getJSON('knxUltimateDpts', (data) => {
|
|
234
|
+
data.forEach(dpt => {
|
|
235
|
+
if (dpt.value.startsWith('1.')) {
|
|
236
|
+
$("#node-input-dptlong_release").append($("<option></option>")
|
|
237
|
+
.attr("value", dpt.value)
|
|
238
|
+
.text(dpt.text))
|
|
239
|
+
$("#node-input-dptdouble_short_release").append($("<option></option>")
|
|
240
|
+
.attr("value", dpt.value)
|
|
241
|
+
.text(dpt.text))
|
|
242
|
+
}
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
$("#node-input-dptlong_release").val(this.dptlong_release)
|
|
246
|
+
$("#node-input-dptdouble_short_release").val(this.dptdouble_short_release)
|
|
247
|
+
|
|
248
|
+
})
|
|
249
|
+
|
|
250
|
+
// Autocomplete suggestion with ETS csv File
|
|
251
|
+
$("#node-input-GAlong_release").autocomplete({
|
|
252
|
+
minLength: 1,
|
|
253
|
+
source: function (request, response) {
|
|
254
|
+
$.getJSON("knxUltimatecsv?nodeID=" + oNodeServer.id, (data) => {
|
|
255
|
+
response($.map(data, function (value, key) {
|
|
256
|
+
var sSearch = (value.ga + " (" + value.devicename + ") DPT" + value.dpt);
|
|
257
|
+
if (fullSearch(sSearch, request.term + " 1.")) {
|
|
258
|
+
return {
|
|
259
|
+
label: value.ga + " # " + value.devicename + " # " + value.dpt, // Label for Display
|
|
260
|
+
value: value.ga // Value
|
|
261
|
+
}
|
|
262
|
+
} else {
|
|
263
|
+
return null;
|
|
264
|
+
}
|
|
265
|
+
}));
|
|
266
|
+
});
|
|
267
|
+
}, select: function (event, ui) {
|
|
268
|
+
// Sets Datapoint and device name automatically
|
|
269
|
+
var sDevName = ui.item.label.split("#")[1].trim();
|
|
270
|
+
try {
|
|
271
|
+
sDevName = sDevName.substr(sDevName.indexOf(")") + 1).trim();
|
|
272
|
+
} catch (error) {
|
|
273
|
+
}
|
|
274
|
+
$('#node-input-namelong_release').val(sDevName);
|
|
275
|
+
var optVal = $("#node-input-dptlong_release option:contains('" + ui.item.label.split("#")[2].trim() + "')").attr('value');
|
|
276
|
+
// Select the option value
|
|
277
|
+
$("#node-input-dptlong_release").val(optVal);
|
|
278
|
+
}
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
// Autocomplete suggestion with ETS csv File
|
|
282
|
+
$("#node-input-GAdouble_short_release").autocomplete({
|
|
283
|
+
minLength: 1,
|
|
284
|
+
source: function (request, response) {
|
|
285
|
+
$.getJSON("knxUltimatecsv?nodeID=" + oNodeServer.id, (data) => {
|
|
286
|
+
response($.map(data, function (value, key) {
|
|
287
|
+
var sSearch = (value.ga + " (" + value.devicename + ") DPT" + value.dpt);
|
|
288
|
+
if (fullSearch(sSearch, request.term + " 1.")) {
|
|
289
|
+
return {
|
|
290
|
+
label: value.ga + " # " + value.devicename + " # " + value.dpt, // Label for Display
|
|
291
|
+
value: value.ga // Value
|
|
292
|
+
}
|
|
293
|
+
} else {
|
|
294
|
+
return null;
|
|
295
|
+
}
|
|
296
|
+
}));
|
|
297
|
+
});
|
|
298
|
+
}, select: function (event, ui) {
|
|
299
|
+
// Sets Datapoint and device name automatically
|
|
300
|
+
var sDevName = ui.item.label.split("#")[1].trim();
|
|
301
|
+
try {
|
|
302
|
+
sDevName = sDevName.substr(sDevName.indexOf(")") + 1).trim();
|
|
303
|
+
} catch (error) {
|
|
304
|
+
}
|
|
305
|
+
$('#node-input-namedouble_short_release').val(sDevName);
|
|
306
|
+
var optVal = $("#node-input-dptdouble_short_release option:contains('" + ui.item.label.split("#")[2].trim() + "')").attr('value');
|
|
307
|
+
// Select the option value
|
|
308
|
+
$("#node-input-dptdouble_short_release").val(optVal);
|
|
309
|
+
}
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
// DPT dptlong_press
|
|
315
|
+
// ########################
|
|
316
|
+
$.getJSON('knxUltimateDpts', (data) => {
|
|
317
|
+
data.forEach(dpt => {
|
|
318
|
+
if (dpt.value.startsWith('1.')) {
|
|
319
|
+
$("#node-input-dptlong_press").append($("<option></option>")
|
|
320
|
+
.attr("value", dpt.value)
|
|
321
|
+
.text(dpt.text))
|
|
322
|
+
}
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
$("#node-input-dptlong_press").val(this.dptlong_press)
|
|
326
|
+
|
|
327
|
+
})
|
|
328
|
+
|
|
329
|
+
// Autocomplete suggestion with ETS csv File
|
|
330
|
+
$("#node-input-GAlong_press").autocomplete({
|
|
331
|
+
minLength: 1,
|
|
332
|
+
source: function (request, response) {
|
|
333
|
+
$.getJSON("knxUltimatecsv?nodeID=" + oNodeServer.id, (data) => {
|
|
334
|
+
response($.map(data, function (value, key) {
|
|
335
|
+
var sSearch = (value.ga + " (" + value.devicename + ") DPT" + value.dpt);
|
|
336
|
+
if (fullSearch(sSearch, request.term + " 1.")) {
|
|
337
|
+
return {
|
|
338
|
+
label: value.ga + " # " + value.devicename + " # " + value.dpt, // Label for Display
|
|
339
|
+
value: value.ga // Value
|
|
340
|
+
}
|
|
341
|
+
} else {
|
|
342
|
+
return null;
|
|
343
|
+
}
|
|
344
|
+
}));
|
|
345
|
+
});
|
|
346
|
+
}, select: function (event, ui) {
|
|
347
|
+
// Sets Datapoint and device name automatically
|
|
348
|
+
var sDevName = ui.item.label.split("#")[1].trim();
|
|
349
|
+
try {
|
|
350
|
+
sDevName = sDevName.substr(sDevName.indexOf(")") + 1).trim();
|
|
351
|
+
} catch (error) {
|
|
352
|
+
}
|
|
353
|
+
$('#node-input-namelong_press').val(sDevName);
|
|
354
|
+
var optVal = $("#node-input-dptlong_press option:contains('" + ui.item.label.split("#")[2].trim() + "')").attr('value');
|
|
355
|
+
// Select the option value
|
|
356
|
+
$("#node-input-dptlong_press").val(optVal);
|
|
357
|
+
}
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
// Autocomplete suggestion with HUE Lights
|
|
366
|
+
$("#node-input-name").autocomplete({
|
|
367
|
+
minLength: 1,
|
|
368
|
+
source: function (request, response) {
|
|
369
|
+
$.getJSON("KNXUltimateGetDevicesHUE?rtype=button&nodeID=" + oNodeServerHue.id, (data) => {
|
|
370
|
+
response($.map(data.devices, function (value, key) {
|
|
371
|
+
//alert(JSON.stringify(value) + " "+ key)
|
|
372
|
+
var sSearch = (value.name);
|
|
373
|
+
if (fullSearch(sSearch, request.term)) {
|
|
374
|
+
return {
|
|
375
|
+
hueDevice: value.id, // Label for Display
|
|
376
|
+
value: value.name // Value
|
|
377
|
+
}
|
|
378
|
+
} else {
|
|
379
|
+
return null;
|
|
380
|
+
}
|
|
381
|
+
}));
|
|
382
|
+
});
|
|
383
|
+
}, select: function (event, ui) {
|
|
384
|
+
// Sets the fields
|
|
385
|
+
$('#node-input-hueDevice').val(ui.item.hueDevice);
|
|
386
|
+
}
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
|
|
390
|
+
// ########################
|
|
391
|
+
|
|
392
|
+
|
|
393
|
+
},
|
|
394
|
+
oneditsave: function () {
|
|
395
|
+
|
|
396
|
+
|
|
397
|
+
},
|
|
398
|
+
oneditcancel: function () {
|
|
399
|
+
|
|
400
|
+
}
|
|
401
|
+
})
|
|
402
|
+
|
|
403
|
+
</script>
|
|
404
|
+
|
|
405
|
+
<script type="text/x-red" data-template-name="knxUltimateHueButton">
|
|
406
|
+
|
|
407
|
+
|
|
408
|
+
<div class="form-row">
|
|
409
|
+
<b>HUE Light</b>  <span style="color:red"
|
|
410
|
+
 <i class="fa fa-question-circle"></i></span>
|
|
411
|
+
 <a target="_blank" href="https://github.com/Supergiovane/node-red-contrib-knx-ultimate/wiki/en-hue-configuration"><u>Configuration</u></a>
|
|
412
|
+
<br />
|
|
413
|
+
<p align="center"><img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-knx-ultimate/master/img/hueButton.png'></p>
|
|
414
|
+
<br />
|
|
415
|
+
<label for="node-input-server" >
|
|
416
|
+
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAKnRFWHRDcmVhdGlvbiBUaW1lAEZyIDYgQXVnIDIwMTAgMjE6NTI6MTkgKzAxMDD84aS8AAAAB3RJTUUH3gYYCicNV+4WIQAAAAlwSFlzAAALEgAACxIB0t1+/AAAAARnQU1BAACxjwv8YQUAAACUSURBVHjaY2CgFZg5c+Z/ZEyWAZ8+f/6/ZsWs/xoamqMGkGrA6Wla/1+fVARjEBuGsSoGmY4eZSCNL59d/g8DIDbIAHR14OgFGQByKjIGKX5+6/T///8gGMQGiV1+/B0Fg70GIkD+RMYgxf/O5/7//2MSmAZhkBi6OrgB6Bg5DGB4ajr3f2xqsYYLSDE2THJUDg0AAAqyDVd4tp4YAAAAAElFTkSuQmCC"></img>
|
|
417
|
+
KNX GW
|
|
418
|
+
</label>
|
|
419
|
+
<input type="text" id="node-input-server" />
|
|
420
|
+
</div>
|
|
421
|
+
|
|
422
|
+
<div class="form-row">
|
|
423
|
+
<label for="node-input-serverHue">
|
|
424
|
+
<img src="data:image/png;base64, iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAERlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAAEKADAAQAAAABAAAAEAAAAAA0VXHyAAABFUlEQVQ4EZWSsWoCQRCG1yiENEFEi6QSkjqWWoqFoBYJ+Br6JHkMn8Iibd4ihQpaJIhWNkry/ZtdGZY78Qa+m39nZ+dm9s4550awglNBluS/gVtAX6KgDclf68w2OThgfR9iT/jnoEv4TtByDThWTCDKW4SSZTf/zj9/eZbN+izTDuKGimu0vPF8B/YN8aC8LmcOj/AAn9CFTEs70Js/oGqy79C69bqJ5XbQI2kGO5N8QL9D08S8zBtBF5ZaVsznpCMoqJnVdjTpb1Db0fwIWmQV6BLXzFOYgA6/gDVfQN9bBWp2J2hdWDPoBV5FrKnAJutHikk/CHHR8i7x4iG7qQ720IYvu3GFbpHjx3pFrOFYkA354z/5bkK826phyAAAAABJRU5ErkJggg=="/>
|
|
425
|
+
HUE Bridge
|
|
426
|
+
</label>
|
|
427
|
+
<input type="text" id="node-input-serverHue" />
|
|
428
|
+
</div>
|
|
429
|
+
|
|
430
|
+
<br/>
|
|
431
|
+
<p>
|
|
432
|
+
<b>Philips HUE</b>
|
|
433
|
+
</p>
|
|
434
|
+
|
|
435
|
+
<div class="form-row">
|
|
436
|
+
<label for="node-input-hueDevice" >
|
|
437
|
+
<i class="fa fa-play-circle"></i> Hue Button</label>
|
|
438
|
+
<input type="text" id="node-input-name" placeholder="Enter your hue device name" />
|
|
439
|
+
<input type="hidden" id="node-input-hueDevice" />
|
|
440
|
+
</div>
|
|
441
|
+
|
|
442
|
+
<br/>
|
|
443
|
+
|
|
444
|
+
<!-- <p> <img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-knx-ultimate/master/img/knx.png' width='32px'> -> <img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-knx-ultimate/master/img/hue.png' width='32px'></p> -->
|
|
445
|
+
|
|
446
|
+
<p>
|
|
447
|
+
<b>PHILIPS HUE BUTTON EVENTS -> TO KNX</b>
|
|
448
|
+
</p>
|
|
449
|
+
|
|
450
|
+
<div class="form-row">
|
|
451
|
+
<label for="node-input-nameinitial_press" style="width:100px;"><i class="fa fa-play-circle-o"></i> Initial press</span></label>
|
|
452
|
+
|
|
453
|
+
<label for="node-input-GAinitial_press" style="width:20px;">GA</label>
|
|
454
|
+
<input type="text" id="node-input-GAinitial_press" placeholder="Ex: 1/1/1" style="width:70px;margin-left: 5px; text-align: left;">
|
|
455
|
+
|
|
456
|
+
<label for="node-input-dptinitial_press" style="width:40px; margin-left: 0px; text-align: right;">dpt</label>
|
|
457
|
+
<select id="node-input-dptinitial_press" style="width:140px;"></select>
|
|
458
|
+
|
|
459
|
+
<label for="node-input-nameinitial_press" style="width:50px; margin-left: 0px; text-align: right;">Name</label>
|
|
460
|
+
<input type="text" id="node-input-nameinitial_press" style="width:200px;margin-left: 5px; text-align: left;">
|
|
461
|
+
</div>
|
|
462
|
+
|
|
463
|
+
<div class="form-row">
|
|
464
|
+
<label for="node-input-namerepeat" style="width:100px;"><i class="fa fa-play-circle-o"></i> Repeat</span></label>
|
|
465
|
+
|
|
466
|
+
<label for="node-input-GArepeat" style="width:20px;">GA</label>
|
|
467
|
+
<input type="text" id="node-input-GArepeat" placeholder="Ex: 1/1/1" style="width:70px;margin-left: 5px; text-align: left;">
|
|
468
|
+
|
|
469
|
+
<label for="node-input-dptrepeat" style="width:40px; margin-left: 0px; text-align: right;">dpt</label>
|
|
470
|
+
<select id="node-input-dptrepeat" style="width:140px;"></select>
|
|
471
|
+
|
|
472
|
+
<label for="node-input-namerepeat" style="width:50px; margin-left: 0px; text-align: right;">Name</label>
|
|
473
|
+
<input type="text" id="node-input-namerepeat" style="width:200px;margin-left: 5px; text-align: left;">
|
|
474
|
+
</div>
|
|
475
|
+
|
|
476
|
+
<div class="form-row">
|
|
477
|
+
<label for="node-input-nameshort_release" style="width:100px;"><i class="fa fa-play-circle-o"></i> Short release</label>
|
|
478
|
+
|
|
479
|
+
<label for="node-input-GAhort_release" style="width:20px;">GA</label>
|
|
480
|
+
<input type="text" id="node-input-GAshort_release" placeholder="Ex: 1/1/1" style="width:70px;margin-left: 5px; text-align: left;">
|
|
481
|
+
|
|
482
|
+
<label for="node-input-dptshort_release" style="width:40px; margin-left: 0px; text-align: right;">dpt</label>
|
|
483
|
+
<select id="node-input-dptshort_release" style="width:140px;"></select>
|
|
484
|
+
|
|
485
|
+
<label for="node-input-nameshort_release" style="width:50px; margin-left: 0px; text-align: right;">Name</label>
|
|
486
|
+
<input type="text" id="node-input-nameshort_release" style="width:200px;margin-left: 5px; text-align: left;">
|
|
487
|
+
</div>
|
|
488
|
+
|
|
489
|
+
<div class="form-row">
|
|
490
|
+
<label for="node-input-namelong_release" style="width:100px;"><i class="fa fa-play-circle-o"></i> Long release</label>
|
|
491
|
+
|
|
492
|
+
<label for="node-input-GAhort_release" style="width:20px;">GA</label>
|
|
493
|
+
<input type="text" id="node-input-GAlong_release" placeholder="Ex: 1/1/1" style="width:70px;margin-left: 5px; text-align: left;">
|
|
494
|
+
|
|
495
|
+
<label for="node-input-dptlong_release" style="width:40px; margin-left: 0px; text-align: right;">dpt</label>
|
|
496
|
+
<select id="node-input-dptlong_release" style="width:140px;"></select>
|
|
497
|
+
|
|
498
|
+
<label for="node-input-namelong_release" style="width:50px; margin-left: 0px; text-align: right;">Name</label>
|
|
499
|
+
<input type="text" id="node-input-namelong_release" style="width:200px;margin-left: 5px; text-align: left;">
|
|
500
|
+
</div>
|
|
501
|
+
|
|
502
|
+
<div class="form-row">
|
|
503
|
+
<label for="node-input-namedouble_short_release" style="width:100px;"><i class="fa fa-play-circle-o"></i> Double short release</label>
|
|
504
|
+
|
|
505
|
+
<label for="node-input-GAdouble_short_release" style="width:20px;">GA</label>
|
|
506
|
+
<input type="text" id="node-input-GAdouble_short_release" placeholder="Ex: 1/1/1" style="width:70px;margin-left: 5px; text-align: left;">
|
|
507
|
+
|
|
508
|
+
<label for="node-input-dptdouble_short_release" style="width:40px; margin-left: 0px; text-align: right;">dpt</label>
|
|
509
|
+
<select id="node-input-dptdouble_short_release" style="width:140px;"></select>
|
|
510
|
+
|
|
511
|
+
<label for="node-input-namedouble_short_release" style="width:50px; margin-left: 0px; text-align: right;"><span data-i18n="knxUltimateHueButton.node-input-name"></span></label>
|
|
512
|
+
<input type="text" id="node-input-namedouble_short_release" style="width:200px;margin-left: 5px; text-align: left;">
|
|
513
|
+
</div>
|
|
514
|
+
|
|
515
|
+
<div class="form-row">
|
|
516
|
+
<label for="node-input-namelong_press" style="width:100px;"><i class="fa fa-play-circle-o"></i> Long press</label>
|
|
517
|
+
|
|
518
|
+
<label for="node-input-GAhort_release" style="width:20px;">GA</label>
|
|
519
|
+
<input type="text" id="node-input-GAlong_press" placeholder="Ex: 1/1/1" style="width:70px;margin-left: 5px; text-align: left;">
|
|
520
|
+
|
|
521
|
+
<label for="node-input-dptlong_press" style="width:40px; margin-left: 0px; text-align: right;">dpt</label>
|
|
522
|
+
<select id="node-input-dptlong_press" style="width:140px;"></select>
|
|
523
|
+
|
|
524
|
+
<label for="node-input-namelong_press" style="width:50px; margin-left: 0px; text-align: right;">Name</label>
|
|
525
|
+
<input type="text" id="node-input-namelong_press" style="width:200px;margin-left: 5px; text-align: left;">
|
|
526
|
+
</div>
|
|
527
|
+
|
|
528
|
+
<div class="form-row">
|
|
529
|
+
<input type="checkbox" id="node-input-toggleValues" style="display:inline-block; width:auto; vertical-align:top;" />
|
|
530
|
+
<label style="width:auto" for="node-input-toggleValues">
|
|
531
|
+
<img
|
|
532
|
+
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAYAAABWdVznAAAACXBIWXMAAB7CAAAewgFu0HU+AAAFGmlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxNDggNzkuMTY0MDM2LCAyMDE5LzA4LzEzLTAxOjA2OjU3ICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgMjEuMSAoTWFjaW50b3NoKSIgeG1wOkNyZWF0ZURhdGU9IjIwMjAtMDMtMjNUMTY6MjM6MjMrMDE6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDIwLTAzLTIzVDE2OjI1OjM0KzAxOjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDIwLTAzLTIzVDE2OjI1OjM0KzAxOjAwIiBkYzpmb3JtYXQ9ImltYWdlL3BuZyIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMyIgcGhvdG9zaG9wOklDQ1Byb2ZpbGU9InNSR0IgSUVDNjE5NjYtMi4xIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOmJmNGM3NWVjLTIwNGYtNGY1YS05YTMxLTQ5NTU5YWJmZDE4NSIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpiZjRjNzVlYy0yMDRmLTRmNWEtOWEzMS00OTU1OWFiZmQxODUiIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDpiZjRjNzVlYy0yMDRmLTRmNWEtOWEzMS00OTU1OWFiZmQxODUiPiA8eG1wTU06SGlzdG9yeT4gPHJkZjpTZXE+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJjcmVhdGVkIiBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOmJmNGM3NWVjLTIwNGYtNGY1YS05YTMxLTQ5NTU5YWJmZDE4NSIgc3RFdnQ6d2hlbj0iMjAyMC0wMy0yM1QxNjoyMzoyMyswMTowMCIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGhvdG9zaG9wIDIxLjEgKE1hY2ludG9zaCkiLz4gPC9yZGY6U2VxPiA8L3htcE1NOkhpc3Rvcnk+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+nhtLUgAAAE9JREFUKJG1UMsOACAIgub//7IdqvVQtjrExU1EEQLuiGCvgTNgl5D74MmVZPu4wIxQAgm+/sDec2VhgQPgf0sq1unjMlYJE/3MZrvy+kMFZQkZEWfC7ikAAAAASUVORK5CYII="></img>
|
|
533
|
+
Toggle values
|
|
534
|
+
</label>
|
|
535
|
+
</div>
|
|
536
|
+
|
|
537
|
+
</div>
|
|
538
|
+
|
|
539
|
+
|
|
540
|
+
<br/>
|
|
541
|
+
<br/>
|
|
542
|
+
<br/>
|
|
543
|
+
<br/>
|
|
544
|
+
<br/>
|
|
545
|
+
<br/>
|
|
546
|
+
<br/>
|
|
547
|
+
<br/>
|
|
548
|
+
|
|
549
|
+
|
|
550
|
+
</script>
|
|
551
|
+
|
|
552
|
+
<script type="text/markdown" data-help-name="knxUltimateHueButton">
|
|
553
|
+
|
|
554
|
+
[Find it useful?](https://www.paypal.me/techtoday)
|
|
555
|
+
|
|
556
|
+
This node lets you get the events of your HUE button.<br/>
|
|
557
|
+
There are many event you can choose from. The relevants one are *short release* and *repeat*.<br/>
|
|
558
|
+
In *short release* you can send true/false to your KNX group address to, for example, toggle a light.<br/>
|
|
559
|
+
In *repeat* event, you can DIM a KNX light.<br/>
|
|
560
|
+
The **toggle values** option is enabled by default. This option toggles the value of each KNX group address (*true/false, increase/decrease dim*))
|
|
561
|
+
|
|
562
|
+
**General**
|
|
563
|
+
|Property|Description|
|
|
564
|
+
|--|--|
|
|
565
|
+
| KNX GW | Select the KNX gateway to be used |
|
|
566
|
+
| HUE Bridge | Select the HUE Bridge to be used |
|
|
567
|
+
| Hue Button | HUE button to be used. The avaiable buttons start showing up while you're typing.|
|
|
568
|
+
|
|
569
|
+
<br/>
|
|
570
|
+
|
|
571
|
+
**PHILIPS HUE BUTTON EVENTS -> TO KNX**
|
|
572
|
+
Here you can get the HUE button events.<br/>
|
|
573
|
+
Start typing in the GA field, the name or group address of your KNX device, the avaiable devices start showing up while you're typing.
|
|
574
|
+
|
|
575
|
+
|Property|Description|
|
|
576
|
+
|--|--|
|
|
577
|
+
| Initial press | As soon as you press your HUE button, this event fires|
|
|
578
|
+
| Repeat | This command is used either to send DIM (increase/decrease) or true/false commands to the KNX group address |
|
|
579
|
+
| Short release | Rapid push of the button, fired as soon as you release your finger from the button. Usually used to toggle a KNX light true/false |
|
|
580
|
+
| Long release | Long press of the button, fired as soon as you release your finger from the button |
|
|
581
|
+
| Long press | Long press of the button, fired as soon as you long press the button |
|
|
582
|
+
| Toggle values | Enable or disable toggling values. If enabled, all values toggles, otherwise, all values are sent as *true* or *increase dim*, to the selected KNX group address. |
|
|
583
|
+
|
|
584
|
+
|
|
585
|
+
<br/>
|
|
586
|
+
</script>
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
module.exports = function (RED) {
|
|
2
|
+
const dptlib = require('./../KNXEngine/dptlib')
|
|
3
|
+
const hueColorConverter = require('./utils/hueColorConverter')
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
async function getLightState(node, _lightID) {
|
|
7
|
+
return new Promise((resolve, reject) => {
|
|
8
|
+
try {
|
|
9
|
+
if (node !== null && node.serverHue !== null && node.serverHue.hueManager !== null) {
|
|
10
|
+
node.serverHue.hueManager.getLight(_lightID).then(ret => {
|
|
11
|
+
node.currentHUEDevice = ret[0]
|
|
12
|
+
resolve(ret)
|
|
13
|
+
})
|
|
14
|
+
}
|
|
15
|
+
} catch (error) {
|
|
16
|
+
reject(error)
|
|
17
|
+
}
|
|
18
|
+
})
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function knxUltimateHueButton(config) {
|
|
22
|
+
RED.nodes.createNode(this, config)
|
|
23
|
+
const node = this
|
|
24
|
+
node.server = RED.nodes.getNode(config.server)
|
|
25
|
+
node.serverHue = RED.nodes.getNode(config.serverHue)
|
|
26
|
+
node.topic = node.name
|
|
27
|
+
node.name = config.name === undefined ? 'Hue' : config.name
|
|
28
|
+
node.outputtopic = node.name
|
|
29
|
+
node.dpt = ''
|
|
30
|
+
node.notifyreadrequest = false
|
|
31
|
+
node.notifyreadrequestalsorespondtobus = 'false'
|
|
32
|
+
node.notifyreadrequestalsorespondtobusdefaultvalueifnotinitialized = ''
|
|
33
|
+
node.notifyresponse = false
|
|
34
|
+
node.notifywrite = true
|
|
35
|
+
node.initialread = true
|
|
36
|
+
node.listenallga = true // Don't remove
|
|
37
|
+
node.outputtype = 'write'
|
|
38
|
+
node.outputRBE = false // Apply or not RBE to the output (Messages coming from flow)
|
|
39
|
+
node.inputRBE = false // Apply or not RBE to the input (Messages coming from BUS)
|
|
40
|
+
node.currentPayload = '' // Current value for the RBE input and for the .previouspayload msg
|
|
41
|
+
node.passthrough = 'no'
|
|
42
|
+
node.formatmultiplyvalue = 1
|
|
43
|
+
node.formatnegativevalue = 'leave'
|
|
44
|
+
node.formatdecimalsvalue = 2
|
|
45
|
+
node.toggle1 = false
|
|
46
|
+
node.toggle2 = false // up or down if repeat field is set to DIM
|
|
47
|
+
node.toggle3 = false
|
|
48
|
+
node.toggle4 = false
|
|
49
|
+
node.toggle4 = false
|
|
50
|
+
node.toggle5 = false
|
|
51
|
+
node.toggle5 = false
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
// Read the state of the light and store it in the holding object
|
|
55
|
+
try {
|
|
56
|
+
if (config.hueLight !== undefined && config.hueLight !== '') getLightState(node, config.hueLight)
|
|
57
|
+
} catch (error) {
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
// Used to call the status update from the config node.
|
|
63
|
+
node.setNodeStatus = ({ fill, shape, text, payload }) => {
|
|
64
|
+
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// This function is called by the knx-ultimate config node, to output a msg.payload.
|
|
68
|
+
node.handleSend = msg => {
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
node.handleSendHUE = _event => {
|
|
72
|
+
try {
|
|
73
|
+
if (_event.id === config.hueDevice) {
|
|
74
|
+
const knxMsgPayload = {}
|
|
75
|
+
if (_event.button.last_event === 'initial_press') {
|
|
76
|
+
knxMsgPayload.ga = config.GAinitial_press
|
|
77
|
+
knxMsgPayload.dpt = config.dptinitial_press
|
|
78
|
+
config.toggleValues ? node.toggle1 = !node.toggle1 : node.toggle1 = true
|
|
79
|
+
knxMsgPayload.payload = node.toggle1
|
|
80
|
+
// Toggle the DIM direction
|
|
81
|
+
config.toggleValues ? node.toggle2 = !node.toggle2 : node.toggle2 = true
|
|
82
|
+
}
|
|
83
|
+
if (_event.button.last_event === 'repeat') {
|
|
84
|
+
knxMsgPayload.ga = config.GArepeat
|
|
85
|
+
knxMsgPayload.dpt = config.dptrepeat
|
|
86
|
+
// True/False or DIM
|
|
87
|
+
if (knxMsgPayload.dpt.startsWith('1.')) {
|
|
88
|
+
config.toggleValues ? node.toggle2 = !node.toggle2 : node.toggle2 = true
|
|
89
|
+
knxMsgPayload.payload = node.toggle2
|
|
90
|
+
}
|
|
91
|
+
if (knxMsgPayload.dpt.startsWith('3.007')) {
|
|
92
|
+
if (!config.toggleValues) node.toggle2 = true
|
|
93
|
+
knxMsgPayload.payload = node.toggle2 ? { decr_incr: 1, data: 5 } : { decr_incr: 0, data: 5 }
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
if (_event.button.last_event === 'short_release') {
|
|
97
|
+
knxMsgPayload.ga = config.GAshort_release
|
|
98
|
+
knxMsgPayload.dpt = config.dptshort_release
|
|
99
|
+
config.toggleValues ? node.toggle3 = !node.toggle3 : node.toggle3 = true
|
|
100
|
+
knxMsgPayload.payload = node.toggle3
|
|
101
|
+
}
|
|
102
|
+
if (_event.button.last_event === 'long_release') {
|
|
103
|
+
knxMsgPayload.ga = config.GAlong_release
|
|
104
|
+
knxMsgPayload.dpt = config.dptlong_release
|
|
105
|
+
config.toggleValues ? node.toggle4 = !node.toggle4 : node.toggle4 = true
|
|
106
|
+
knxMsgPayload.payload = node.toggle4
|
|
107
|
+
}
|
|
108
|
+
if (_event.button.last_event === 'double_short_release') {
|
|
109
|
+
knxMsgPayload.ga = config.GAdouble_short_release
|
|
110
|
+
knxMsgPayload.dpt = config.dptdouble_short_release
|
|
111
|
+
config.toggleValues ? node.toggle5 = !node.toggle5 : node.toggle5 = true
|
|
112
|
+
knxMsgPayload.payload = node.toggle5
|
|
113
|
+
}
|
|
114
|
+
if (_event.button.last_event === 'long_press') {
|
|
115
|
+
knxMsgPayload.ga = config.GAlong_press
|
|
116
|
+
knxMsgPayload.dpt = config.dptlong_press
|
|
117
|
+
config.toggleValues ? node.toggle6 = !node.toggle6 : node.toggle6 = true
|
|
118
|
+
knxMsgPayload.payload = node.toggle6
|
|
119
|
+
}
|
|
120
|
+
// Send to KNX bus
|
|
121
|
+
if (knxMsgPayload.ga !== undefined) {
|
|
122
|
+
node.status({ fill: 'green', shape: 'dot', text: 'HUE->KNX ' + _event.button.last_event + ' ' + JSON.stringify(knxMsgPayload.payload) + ' (' + new Date().getDate() + ', ' + new Date().toLocaleTimeString() + ')' })
|
|
123
|
+
if (knxMsgPayload.ga !== '' && knxMsgPayload.ga !== undefined) node.server.writeQueueAdd({ grpaddr: knxMsgPayload.ga, payload: knxMsgPayload.payload, dpt: knxMsgPayload.dpt, outputtype: 'write', nodecallerid: node.id })
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
} catch (error) {
|
|
127
|
+
node.status({ fill: 'red', shape: 'dot', text: 'HUE->KNX error ' + error.message + ' (' + new Date().getDate() + ', ' + new Date().toLocaleTimeString() + ')' })
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// On each deploy, unsubscribe+resubscribe
|
|
132
|
+
if (node.server) {
|
|
133
|
+
node.server.removeClient(node)
|
|
134
|
+
node.server.addClient(node)
|
|
135
|
+
}
|
|
136
|
+
if (node.serverHue) {
|
|
137
|
+
node.serverHue.removeClient(node)
|
|
138
|
+
node.serverHue.addClient(node)
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
node.on('input', function (msg) {
|
|
142
|
+
|
|
143
|
+
})
|
|
144
|
+
|
|
145
|
+
node.on('close', function (done) {
|
|
146
|
+
if (node.server) {
|
|
147
|
+
node.server.removeClient(node)
|
|
148
|
+
}
|
|
149
|
+
done()
|
|
150
|
+
})
|
|
151
|
+
|
|
152
|
+
// On each deploy, unsubscribe+resubscribe
|
|
153
|
+
if (node.server) {
|
|
154
|
+
node.server.removeClient(node)
|
|
155
|
+
node.server.addClient(node)
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
RED.nodes.registerType('knxUltimateHueButton', knxUltimateHueButton)
|
|
159
|
+
}
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
//buttonState: {value: true},
|
|
7
7
|
server: { type: "knxUltimate-config", required: true },
|
|
8
8
|
serverHue: { type: "hue-config", required: true },
|
|
9
|
-
name: { value: "Hue Light" },
|
|
9
|
+
name: { value: "Hue Light (beta)" },
|
|
10
10
|
|
|
11
11
|
nameLightSwitch: { value: "" },
|
|
12
12
|
GALightSwitch: { value: "" },
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
GALightBrightnessState: { value: "" },
|
|
37
37
|
dptLightBrightnessState: { value: "" },
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
hueDevice: { value: "" }
|
|
40
40
|
},
|
|
41
41
|
inputs: 0,
|
|
42
42
|
outputs: 0,
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
label: function () {
|
|
45
45
|
return (this.name);
|
|
46
46
|
},
|
|
47
|
-
paletteLabel: "Hue Light
|
|
47
|
+
paletteLabel: "Hue Light",
|
|
48
48
|
// button: {
|
|
49
49
|
// enabled: function() {
|
|
50
50
|
// // return whether or not the button is enabled, based on the current
|
|
@@ -62,6 +62,7 @@
|
|
|
62
62
|
oneditprepare: function () {
|
|
63
63
|
var node = this;
|
|
64
64
|
var oNodeServer = RED.nodes.node($("#node-input-server").val()); // Store the config-node
|
|
65
|
+
var oNodeServerHue = RED.nodes.node($("#node-input-serverHue").val()); // Store the config-node
|
|
65
66
|
|
|
66
67
|
// 19/02/2020 Used to get the server sooner als deploy.
|
|
67
68
|
$("#node-input-server").change(function () {
|
|
@@ -69,6 +70,12 @@
|
|
|
69
70
|
oNodeServer = RED.nodes.node($(this).val());
|
|
70
71
|
} catch (error) { }
|
|
71
72
|
});
|
|
73
|
+
// 19/02/2020 Used to get the server sooner als deploy.
|
|
74
|
+
$("#node-input-serverHue").change(function () {
|
|
75
|
+
try {
|
|
76
|
+
oNodeServerHue = RED.nodes.node($(this).val());
|
|
77
|
+
} catch (error) { }
|
|
78
|
+
});
|
|
72
79
|
|
|
73
80
|
// 31/03/2020 Search Helper
|
|
74
81
|
function fullSearch(sourceText, searchString) {
|
|
@@ -391,17 +398,17 @@
|
|
|
391
398
|
|
|
392
399
|
|
|
393
400
|
// Autocomplete suggestion with HUE Lights
|
|
394
|
-
$("#node-input-
|
|
401
|
+
$("#node-input-name").autocomplete({
|
|
395
402
|
minLength: 1,
|
|
396
403
|
source: function (request, response) {
|
|
397
|
-
$.getJSON("
|
|
398
|
-
response($.map(data.
|
|
404
|
+
$.getJSON("KNXUltimateGetDevicesHUE?rtype=light&nodeID=" + oNodeServerHue.id, (data) => {
|
|
405
|
+
response($.map(data.devices, function (value, key) {
|
|
399
406
|
//alert(JSON.stringify(value) + " "+ key)
|
|
400
|
-
var sSearch = (value.
|
|
407
|
+
var sSearch = (value.name);
|
|
401
408
|
if (fullSearch(sSearch, request.term)) {
|
|
402
409
|
return {
|
|
403
|
-
|
|
404
|
-
value: value.
|
|
410
|
+
hueDevice: value.id, // Label for Display
|
|
411
|
+
value: value.name // Value
|
|
405
412
|
}
|
|
406
413
|
} else {
|
|
407
414
|
return null;
|
|
@@ -409,10 +416,8 @@
|
|
|
409
416
|
}));
|
|
410
417
|
});
|
|
411
418
|
}, select: function (event, ui) {
|
|
412
|
-
// Sets the
|
|
413
|
-
|
|
414
|
-
$('#node-input-hueLight').val(sDevName);
|
|
415
|
-
$('#node-input-name').val(sDevName.split("#")[0]);
|
|
419
|
+
// Sets the fields
|
|
420
|
+
$('#node-input-hueDevice').val(ui.item.hueDevice);
|
|
416
421
|
}
|
|
417
422
|
});
|
|
418
423
|
|
|
@@ -436,32 +441,27 @@
|
|
|
436
441
|
|
|
437
442
|
|
|
438
443
|
<div class="form-row">
|
|
439
|
-
<b
|
|
440
|
-
|
|
444
|
+
<b>HUE Light</b>  <span style="color:red"
|
|
445
|
+
 <i class="fa fa-question-circle"></i></span>
|
|
446
|
+
 <a target="_blank" href="https://github.com/Supergiovane/node-red-contrib-knx-ultimate/wiki/en-hue-configuration"><u>Configuration</u></a>
|
|
441
447
|
<br />
|
|
448
|
+
<p align="center"><img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-knx-ultimate/master/img/hueLight.png'></p>
|
|
442
449
|
<br />
|
|
443
450
|
<label for="node-input-server" >
|
|
444
|
-
<
|
|
445
|
-
|
|
451
|
+
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAKnRFWHRDcmVhdGlvbiBUaW1lAEZyIDYgQXVnIDIwMTAgMjE6NTI6MTkgKzAxMDD84aS8AAAAB3RJTUUH3gYYCicNV+4WIQAAAAlwSFlzAAALEgAACxIB0t1+/AAAAARnQU1BAACxjwv8YQUAAACUSURBVHjaY2CgFZg5c+Z/ZEyWAZ8+f/6/ZsWs/xoamqMGkGrA6Wla/1+fVARjEBuGsSoGmY4eZSCNL59d/g8DIDbIAHR14OgFGQByKjIGKX5+6/T///8gGMQGiV1+/B0Fg70GIkD+RMYgxf/O5/7//2MSmAZhkBi6OrgB6Bg5DGB4ajr3f2xqsYYLSDE2THJUDg0AAAqyDVd4tp4YAAAAAElFTkSuQmCC"></img>
|
|
452
|
+
KNX GW
|
|
446
453
|
</label>
|
|
447
454
|
<input type="text" id="node-input-server" />
|
|
448
455
|
</div>
|
|
449
456
|
|
|
450
457
|
<div class="form-row">
|
|
451
458
|
<label for="node-input-serverHue">
|
|
452
|
-
<
|
|
453
|
-
|
|
459
|
+
<img src="data:image/png;base64, iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAERlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAAEKADAAQAAAABAAAAEAAAAAA0VXHyAAABFUlEQVQ4EZWSsWoCQRCG1yiENEFEi6QSkjqWWoqFoBYJ+Br6JHkMn8Iibd4ihQpaJIhWNkry/ZtdGZY78Qa+m39nZ+dm9s4550awglNBluS/gVtAX6KgDclf68w2OThgfR9iT/jnoEv4TtByDThWTCDKW4SSZTf/zj9/eZbN+izTDuKGimu0vPF8B/YN8aC8LmcOj/AAn9CFTEs70Js/oGqy79C69bqJ5XbQI2kGO5N8QL9D08S8zBtBF5ZaVsznpCMoqJnVdjTpb1Db0fwIWmQV6BLXzFOYgA6/gDVfQN9bBWp2J2hdWDPoBV5FrKnAJutHikk/CHHR8i7x4iG7qQ720IYvu3GFbpHjx3pFrOFYkA354z/5bkK826phyAAAAABJRU5ErkJggg=="/>
|
|
460
|
+
HUE Bridge
|
|
454
461
|
</label>
|
|
455
462
|
<input type="text" id="node-input-serverHue" />
|
|
456
463
|
</div>
|
|
457
464
|
|
|
458
|
-
<div class="form-row">
|
|
459
|
-
<label for="node-input-name" >
|
|
460
|
-
<i class="fa fa-tag"></i>
|
|
461
|
-
<span data-i18n="knxUltimateHueLight.node-input-name"></span>
|
|
462
|
-
</label>
|
|
463
|
-
<input style="width:35%;" type="text" id="node-input-name" data-i18n="[placeholder]knxUltimateHueLight.node-input-name" />
|
|
464
|
-
</div>
|
|
465
465
|
|
|
466
466
|
<br/>
|
|
467
467
|
<p>
|
|
@@ -469,9 +469,10 @@
|
|
|
469
469
|
</p>
|
|
470
470
|
|
|
471
471
|
<div class="form-row">
|
|
472
|
-
<label for="node-input-
|
|
473
|
-
<i class="fa fa-
|
|
474
|
-
<input type="text" id="node-input-
|
|
472
|
+
<label for="node-input-hueDevice" >
|
|
473
|
+
<i class="fa fa-play-circle"></i> Name</label>
|
|
474
|
+
<input type="text" id="node-input-name" placeholder="Enter your hue device name"/>
|
|
475
|
+
<input type="hidden" id="node-input-hueDevice"/>
|
|
475
476
|
</div>
|
|
476
477
|
|
|
477
478
|
<br/>
|
|
@@ -496,7 +497,7 @@
|
|
|
496
497
|
</div>
|
|
497
498
|
</div>
|
|
498
499
|
<div class="form-row">
|
|
499
|
-
<label for="node-input-nameLightDIM" style="width:100px;"><i class="fa fa-play-circle-o"></i
|
|
500
|
+
<label for="node-input-nameLightDIM" style="width:100px;"><i class="fa fa-play-circle-o"></i> Dimming</label>
|
|
500
501
|
|
|
501
502
|
<label for="node-input-GALightDIM" style="width:20px;"><span data-i18n="knxUltimateHueLight.node-input-GALightState"></span></label>
|
|
502
503
|
<input type="text" id="node-input-GALightDIM" placeholder="Ex: 1/1/1" style="width:70px;margin-left: 5px; text-align: left;">
|
|
@@ -540,13 +541,13 @@
|
|
|
540
541
|
|
|
541
542
|
<br/>
|
|
542
543
|
<p>
|
|
543
|
-
<b>PHILIPS HUE
|
|
544
|
+
<b>PHILIPS HUE LIGHT STATE -> TO KNX</b>
|
|
544
545
|
</p>
|
|
545
546
|
|
|
546
547
|
<div class="form-row">
|
|
547
|
-
<label for="node-input-nameLightState" style="width:100px;"><i class="fa fa-play-circle-o"></i>
|
|
548
|
+
<label for="node-input-nameLightState" style="width:100px;"><i class="fa fa-play-circle-o"></i> Switch</label>
|
|
548
549
|
|
|
549
|
-
<label for="node-input-GALightState" style="width:20px;"
|
|
550
|
+
<label for="node-input-GALightState" style="width:20px;">GA</label>
|
|
550
551
|
<input type="text" id="node-input-GALightState" placeholder="Ex: 1/1/1" style="width:70px;margin-left: 5px; text-align: left;">
|
|
551
552
|
|
|
552
553
|
<label for="node-input-dptLightState" style="width:40px; margin-left: 0px; text-align: right;">
|
|
@@ -557,7 +558,7 @@
|
|
|
557
558
|
<input type="text" id="node-input-nameLightState" style="width:200px;margin-left: 5px; text-align: left;">
|
|
558
559
|
</div>
|
|
559
560
|
<div class="form-row">
|
|
560
|
-
<label for="node-input-nameLightColorState" style="width:100px;"><i class="fa fa-play-circle-o"></i> Color
|
|
561
|
+
<label for="node-input-nameLightColorState" style="width:100px;"><i class="fa fa-play-circle-o"></i> Color</label>
|
|
561
562
|
|
|
562
563
|
<label for="node-input-GALightColorState" style="width:20px;"><span data-i18n="knxUltimateHueLight.node-input-GALightState"></span></label>
|
|
563
564
|
<input type="text" id="node-input-GALightColorState" placeholder="Ex: 1/1/1" style="width:70px;margin-left: 5px; text-align: left;">
|
|
@@ -571,7 +572,7 @@
|
|
|
571
572
|
</div>
|
|
572
573
|
</div>
|
|
573
574
|
<div class="form-row">
|
|
574
|
-
<label for="node-input-nameLightBrightnessState" style="width:100px;"><i class="fa fa-play-circle-o"></i> Brightness
|
|
575
|
+
<label for="node-input-nameLightBrightnessState" style="width:100px;"><i class="fa fa-play-circle-o"></i> Brightness</label>
|
|
575
576
|
|
|
576
577
|
<label for="node-input-GALightBrightnessState" style="width:20px;"><span data-i18n="knxUltimateHueLight.node-input-GALightState"></span></label>
|
|
577
578
|
<input type="text" id="node-input-GALightBrightnessState" placeholder="Ex: 1/1/1" style="width:70px;margin-left: 5px; text-align: left;">
|
|
@@ -594,4 +595,46 @@
|
|
|
594
595
|
<br/>
|
|
595
596
|
|
|
596
597
|
|
|
598
|
+
</script>
|
|
599
|
+
|
|
600
|
+
|
|
601
|
+
<script type="text/markdown" data-help-name="knxUltimateHueLight">
|
|
602
|
+
|
|
603
|
+
[Find it useful?](https://www.paypal.me/techtoday)
|
|
604
|
+
|
|
605
|
+
This node lets you control your Philips HUE light and also get the states of this lights.
|
|
606
|
+
|
|
607
|
+
**General**
|
|
608
|
+
|Property|Description|
|
|
609
|
+
|--|--|
|
|
610
|
+
| KNX GW | Select the KNX gateway to be used |
|
|
611
|
+
| HUE Bridge | Select the HUE Bridge to be used |
|
|
612
|
+
| Name | HUE light to be used. The avaiable lights start showing up while you're typing.|
|
|
613
|
+
|
|
614
|
+
<br/>
|
|
615
|
+
|
|
616
|
+
**KNX COMMANDS -> TO PHILIPS HUE**
|
|
617
|
+
Here you can choose the KNX addresses to be linked to the avaiable HUE light commands.<br/>
|
|
618
|
+
Start typing in the GA field, the name or group address of your KNX device, the avaiable devices start showing up while you're typing.
|
|
619
|
+
|
|
620
|
+
|Property|Description|
|
|
621
|
+
|--|--|
|
|
622
|
+
| Switch | This command is used to turn on/off the HUE light via a boolean KNX value true/false|
|
|
623
|
+
| Dimming | This command is used to DIM the HUE light via a KNX relative DIM datapoint |
|
|
624
|
+
| Color | This command is used to change the HUE light's color. Accepted datapoint is RGB triplet (r,g,b)|
|
|
625
|
+
| Brightness | This command is used to change the absolute HUE light's brightness |
|
|
626
|
+
|
|
627
|
+
<br/>
|
|
628
|
+
|
|
629
|
+
**PHILIPS HUE LIGHT STATE -> TO KNX**
|
|
630
|
+
Here you can link the state changes of your HUE light, to any KNX group address you want.<br/>
|
|
631
|
+
Start typing in the GA field, the name or group address of your KNX device, the avaiable devices start showing up while you're typing.
|
|
632
|
+
|
|
633
|
+
|Property|Description|
|
|
634
|
+
|--|--|
|
|
635
|
+
| Switch | This state is used to send on/off value to the selected KNX group address |
|
|
636
|
+
| Color | This state is used to send changes of the HUE light's color. Accepted datapoint is RGB triplet (r,g,b)|
|
|
637
|
+
| Brightness | This state is used to send changes of your absolute HUE light's brightness, to a KNX group address |
|
|
638
|
+
|
|
639
|
+
<br/>
|
|
597
640
|
</script>
|
|
@@ -3,13 +3,15 @@ module.exports = function (RED) {
|
|
|
3
3
|
const hueColorConverter = require('./utils/hueColorConverter')
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
async function getLightState(node,
|
|
6
|
+
async function getLightState(node, _lightID) {
|
|
7
7
|
return new Promise((resolve, reject) => {
|
|
8
8
|
try {
|
|
9
|
-
node.serverHue.hueManager
|
|
10
|
-
node.
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
if (node !== null && node.serverHue !== null && node.serverHue.hueManager !== null) {
|
|
10
|
+
node.serverHue.hueManager.getLight(_lightID).then(ret => {
|
|
11
|
+
node.currentHUEDevice = ret[0]
|
|
12
|
+
resolve(ret)
|
|
13
|
+
})
|
|
14
|
+
}
|
|
13
15
|
} catch (error) {
|
|
14
16
|
reject(error)
|
|
15
17
|
}
|
|
@@ -45,7 +47,7 @@ module.exports = function (RED) {
|
|
|
45
47
|
|
|
46
48
|
// Read the state of the light and store it in the holding object
|
|
47
49
|
try {
|
|
48
|
-
getLightState(node, config)
|
|
50
|
+
if (config.hueDevice !== undefined && config.hueDevice !== '') getLightState(node, config.hueDevice)
|
|
49
51
|
} catch (error) {
|
|
50
52
|
}
|
|
51
53
|
|
|
@@ -64,26 +66,26 @@ module.exports = function (RED) {
|
|
|
64
66
|
case config.GALightSwitch:
|
|
65
67
|
msg.payload = dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptLightSwitch))
|
|
66
68
|
state = msg.payload === true ? { on: { on: true } } : { on: { on: false } }
|
|
67
|
-
node.serverHue.hueManager.setLightState(config.
|
|
69
|
+
node.serverHue.hueManager.setLightState(config.hueDevice, state)
|
|
68
70
|
break
|
|
69
71
|
case config.GALightDIM:
|
|
70
72
|
msg.payload = dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptLightDIM))
|
|
71
73
|
state = msg.payload.decr_incr === 1 ? { dimming_delta: { action: 'up', brightness_delta: 20 } } : { dimming_delta: { action: 'down', brightness_delta: 20 } }
|
|
72
|
-
node.serverHue.hueManager.setLightState(config.
|
|
74
|
+
node.serverHue.hueManager.setLightState(config.hueDevice, state)
|
|
73
75
|
break
|
|
74
76
|
case config.GALightBrightness:
|
|
75
77
|
msg.payload = dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptLightBrightness))
|
|
76
78
|
state = { dimming: { brightness: msg.payload } }
|
|
77
|
-
node.serverHue.hueManager.setLightState(config.
|
|
79
|
+
node.serverHue.hueManager.setLightState(config.hueDevice, state)
|
|
78
80
|
break
|
|
79
81
|
case config.GALightColor:
|
|
80
82
|
// Behavior like ISE HUE CONNECT, by setting the brightness and on/off as well
|
|
81
83
|
msg.payload = dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptLightColor))
|
|
82
|
-
const gamut = node.
|
|
84
|
+
const gamut = node.currentHUEDevice.color.gamut_type || null
|
|
83
85
|
const retXY = hueColorConverter.ColorConverter.rgbToXy(msg.payload.red, msg.payload.green, msg.payload.blue, gamut)
|
|
84
86
|
const bright = hueColorConverter.ColorConverter.getBrightnessFromRGB(msg.payload.red, msg.payload.green, msg.payload.blue)
|
|
85
87
|
bright > 0 ? state = { on: { on: true }, dimming: { brightness: bright }, color: { xy: retXY } } : state = { on: { on: false } }
|
|
86
|
-
node.serverHue.hueManager.setLightState(config.
|
|
88
|
+
node.serverHue.hueManager.setLightState(config.hueDevice, state)
|
|
87
89
|
break
|
|
88
90
|
default:
|
|
89
91
|
break
|
|
@@ -96,7 +98,7 @@ module.exports = function (RED) {
|
|
|
96
98
|
|
|
97
99
|
node.handleSendHUE = _event => {
|
|
98
100
|
try {
|
|
99
|
-
if (_event.id === config.
|
|
101
|
+
if (_event.id === config.hueDevice) {
|
|
100
102
|
let knxMsgPayload = {}
|
|
101
103
|
if (_event.hasOwnProperty('on')) {
|
|
102
104
|
knxMsgPayload.ga = config.GALightState
|
|
@@ -106,7 +108,7 @@ module.exports = function (RED) {
|
|
|
106
108
|
if (_event.hasOwnProperty('color')) {
|
|
107
109
|
knxMsgPayload.ga = config.GALightColorState
|
|
108
110
|
knxMsgPayload.dpt = config.dptLightColorState
|
|
109
|
-
knxMsgPayload.payload = hueColorConverter.ColorConverter.xyBriToRgb(_event.color.xy.x, _event.color.xy.y, node.
|
|
111
|
+
knxMsgPayload.payload = hueColorConverter.ColorConverter.xyBriToRgb(_event.color.xy.x, _event.color.xy.y, node.currentHUEDevice.dimming.brightness)
|
|
110
112
|
}
|
|
111
113
|
if (_event.hasOwnProperty('dimming')) {
|
|
112
114
|
knxMsgPayload.ga = config.GALightBrightnessState
|
|
@@ -116,7 +118,7 @@ module.exports = function (RED) {
|
|
|
116
118
|
// Send to KNX bus
|
|
117
119
|
if (knxMsgPayload.ga !== undefined) {
|
|
118
120
|
node.status({ fill: 'green', shape: 'dot', text: 'HUE->KNX State ' + JSON.stringify(knxMsgPayload.payload) + ' (' + new Date().getDate() + ', ' + new Date().toLocaleTimeString() + ')' })
|
|
119
|
-
if (
|
|
121
|
+
if (knxMsgPayload.ga !== '' && knxMsgPayload.ga !== undefined) node.server.writeQueueAdd({ grpaddr: knxMsgPayload.ga, payload: knxMsgPayload.payload, dpt: knxMsgPayload.dpt, outputtype: 'write', nodecallerid: node.id })
|
|
120
122
|
}
|
|
121
123
|
}
|
|
122
124
|
} catch (error) {
|
package/nodes/utils/hueUtils.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
//const hueApi = require('node-hue-api')
|
|
3
|
+
// const hueApi = require('node-hue-api')
|
|
4
4
|
const hueApiV2 = require('node-hue')
|
|
5
5
|
const { EventEmitter } = require('events')
|
|
6
6
|
|
|
@@ -16,28 +16,34 @@ class classHUE extends EventEmitter {
|
|
|
16
16
|
this.hue = undefined
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
// Get all devices and join it with relative rooms, by adding the room name to the device name
|
|
20
|
+
getDevices = async (_rtype) => {
|
|
20
21
|
try {
|
|
21
22
|
// V2
|
|
22
23
|
const hue = hueApiV2.connect({ host: this.HUEBridgeIP, key: this.username })
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
//
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
24
|
+
const retArray = []
|
|
25
|
+
const allResources = await hue.getResources()
|
|
26
|
+
const allRooms = await hue.getRooms()
|
|
27
|
+
const newArray = allResources.filter(x => x.type === _rtype)
|
|
28
|
+
// Add room name to the device name
|
|
29
|
+
newArray.forEach(device => {
|
|
30
|
+
// const Room = allRooms.find(room => {
|
|
31
|
+
// return room.children.find(child => child.rid === device.id)
|
|
32
|
+
// })
|
|
33
|
+
const Room = allRooms.find(room => room.children.find(child => child.rid === device.owner.rid))
|
|
34
|
+
const linkedDevName = allResources.find(dev => dev.type === 'device' && dev.services.find(serv => serv.rid === device.id)).metadata.name || ''
|
|
35
|
+
if (_rtype === 'button') {
|
|
36
|
+
const controlID = device.metadata !== undefined ? (device.metadata.control_id || '') : ''
|
|
37
|
+
retArray.push({ name: linkedDevName + (controlID !== '' ? ', button ' + controlID : '') + (Room !== undefined ? ', room ' + Room.metadata.name : ''), id: device.id })
|
|
38
|
+
}
|
|
39
|
+
if (_rtype === 'light') {
|
|
40
|
+
retArray.push({ name: linkedDevName + (Room !== undefined ? ', room ' + Room.metadata.name : ''), id: device.id })
|
|
41
|
+
}
|
|
42
|
+
})
|
|
43
|
+
return { devices: retArray }
|
|
38
44
|
} catch (error) {
|
|
39
|
-
console.log('KNXUltimateHue: classHUE: error ' + error.message)
|
|
40
|
-
return ({
|
|
45
|
+
console.log('KNXUltimateHue: HueUtils: classHUE: getDevices: error ' + error.message)
|
|
46
|
+
return ({ devices: error.message })
|
|
41
47
|
}
|
|
42
48
|
}
|
|
43
49
|
|
|
@@ -69,7 +75,7 @@ class classHUE extends EventEmitter {
|
|
|
69
75
|
handleTheDog = async () => {
|
|
70
76
|
this.timerWatchDog = setInterval(async () => {
|
|
71
77
|
try {
|
|
72
|
-
//const hue = hueApiV2.connect({ host: this.HUEBridgeIP, key: this.username })
|
|
78
|
+
// const hue = hueApiV2.connect({ host: this.HUEBridgeIP, key: this.username })
|
|
73
79
|
if (this.hue !== undefined) {
|
|
74
80
|
const sRet = await this.hue.getBridges()
|
|
75
81
|
if (sRet.filter(e => e.bridge_id.toString().toLowerCase() === this.bridgeid.toString().toLowerCase()).length === 0) {
|
|
@@ -107,4 +113,3 @@ class classHUE extends EventEmitter {
|
|
|
107
113
|
}
|
|
108
114
|
}
|
|
109
115
|
module.exports.classHUE = classHUE
|
|
110
|
-
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-red-contrib-knx-ultimate",
|
|
3
|
-
"version": "2.0.
|
|
4
|
-
"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.",
|
|
3
|
+
"version": "2.0.2",
|
|
4
|
+
"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 handling.",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"mkdirp": "1.0.4",
|
|
7
7
|
"ping": "0.4.1",
|
|
@@ -29,7 +29,8 @@
|
|
|
29
29
|
"knxUltimateLoadControl": "/nodes/knxUltimateLoadControl.js",
|
|
30
30
|
"knxUltimateViewer": "/nodes/knxUltimateViewer.js",
|
|
31
31
|
"hueConfig": "/nodes/hue-config.js",
|
|
32
|
-
"knxUltimateHueLight": "/nodes/knxUltimateHueLight.js"
|
|
32
|
+
"knxUltimateHueLight": "/nodes/knxUltimateHueLight.js",
|
|
33
|
+
"knxUltimateHueButton": "/nodes/knxUltimateHueButton.js"
|
|
33
34
|
}
|
|
34
35
|
},
|
|
35
36
|
"repository": {
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
<script type="text/x-red" data-help-name="knxUltimateHueLight">
|
|
2
|
-
<h1>KNX Ultimate - Nodo HUE</h1>
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
<p>
|
|
7
|
-
<a href="https://www.paypal.me/techtoday" target="_blank"><img src='https://img.shields.io/badge/Donate-PayPal-blue.svg?style=flat-square' width='30%'></a>
|
|
8
|
-
|
|
9
|
-
</p>
|
|
10
|
-
</script>
|