node-red-contrib-knx-ultimate 2.2.6 → 2.2.10
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 +15 -0
- package/nodes/hue-config.js +21 -20
- package/nodes/knxUltimate-config.html +3 -3
- package/nodes/knxUltimate-config.js +1 -1
- package/nodes/knxUltimateHueBattery.html +1 -1
- package/nodes/knxUltimateHueButton.html +1 -10
- package/nodes/knxUltimateHueButton.js +1 -1
- package/nodes/knxUltimateHueLight.html +548 -483
- package/nodes/knxUltimateHueLight.js +75 -35
- package/nodes/knxUltimateHueLightSensor.html +1 -1
- package/nodes/knxUltimateHueMotion.html +1 -11
- package/nodes/knxUltimateHueMotion.js +1 -1
- package/nodes/knxUltimateHueScene.html +32 -9
- package/nodes/knxUltimateHueScene.js +28 -22
- package/nodes/knxUltimateHueTapDial.html +1 -13
- package/nodes/knxUltimateHueTapDial.js +1 -1
- package/nodes/knxUltimateHueTemperatureSensor.html +11 -11
- package/nodes/knxUltimateSceneController.js +4 -5
- package/nodes/utils/hueColorConverter.js +2 -0
- package/package.json +1 -1
- package/resources/11f26b4500.js +2 -0
- package/resources/iro@5 +7 -0
|
@@ -60,9 +60,9 @@ module.exports = function (RED) {
|
|
|
60
60
|
node.handleSend = (msg) => {
|
|
61
61
|
if (node.currentHUEDevice === undefined) {
|
|
62
62
|
node.setNodeStatusHue({
|
|
63
|
-
fill: "
|
|
63
|
+
fill: "grey",
|
|
64
64
|
shape: "ring",
|
|
65
|
-
text: "
|
|
65
|
+
text: "Initializing. Please wait.",
|
|
66
66
|
payload: "",
|
|
67
67
|
});
|
|
68
68
|
return;
|
|
@@ -126,6 +126,18 @@ module.exports = function (RED) {
|
|
|
126
126
|
fill: "green", shape: "dot", text: "KNX->HUE", payload: JSON.stringify(msg.payload),
|
|
127
127
|
});
|
|
128
128
|
break;
|
|
129
|
+
case config.GALightKelvin:
|
|
130
|
+
msg.payload = dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptLightKelvin));
|
|
131
|
+
let retMirek = hueColorConverter.ColorConverter.scale(msg.payload, [0, 65535], [153, 500]);
|
|
132
|
+
state = { color_temperature: { mirek: retMirek } };
|
|
133
|
+
node.serverHue.hueManager.writeHueQueueAdd(node.hueDevice, state, node.isGrouped_light === false ? "setLight" : "setGroupedLight");
|
|
134
|
+
node.setNodeStatusHue({
|
|
135
|
+
fill: "green",
|
|
136
|
+
shape: "dot",
|
|
137
|
+
text: "KNX->HUE",
|
|
138
|
+
payload: state,
|
|
139
|
+
});
|
|
140
|
+
break;
|
|
129
141
|
case config.GADaylightSensor:
|
|
130
142
|
if (config.enableDayNightLighting === "yes") {
|
|
131
143
|
node.DayTime = Boolean(dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptDaylightSensor)));
|
|
@@ -168,12 +180,6 @@ module.exports = function (RED) {
|
|
|
168
180
|
payload: state,
|
|
169
181
|
});
|
|
170
182
|
}
|
|
171
|
-
node.setNodeStatusHue({
|
|
172
|
-
fill: "green",
|
|
173
|
-
shape: "dot",
|
|
174
|
-
text: "KNX->HUE",
|
|
175
|
-
payload: msg.payload,
|
|
176
|
-
});
|
|
177
183
|
break;
|
|
178
184
|
case config.GALightBrightness:
|
|
179
185
|
msg.payload = dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptLightBrightness));
|
|
@@ -424,6 +430,9 @@ module.exports = function (RED) {
|
|
|
424
430
|
// IMPORTANT: exit if no button last_event present.
|
|
425
431
|
if (_event.initializingAtStart === true && node.readStatusAtStartup === "no") return;
|
|
426
432
|
|
|
433
|
+
// Output the msg to the flow
|
|
434
|
+
node.send(_event);
|
|
435
|
+
|
|
427
436
|
if (_event.hasOwnProperty("on")) {
|
|
428
437
|
node.updateKNXLightState(_event.on.on);
|
|
429
438
|
// In case of switch off, set the dim to zero
|
|
@@ -433,13 +442,6 @@ module.exports = function (RED) {
|
|
|
433
442
|
) {
|
|
434
443
|
node.updateKNXBrightnessState(0);
|
|
435
444
|
node.currentHUEDevice.dimming.brightness = 0;
|
|
436
|
-
} else {
|
|
437
|
-
// // Sends the previous brightness value
|
|
438
|
-
// try {
|
|
439
|
-
// node.updateKNXBrightnessState(node.currentHUEDevice.dimming.brightness);
|
|
440
|
-
// } catch (error) {
|
|
441
|
-
// /* empty */
|
|
442
|
-
// }
|
|
443
445
|
}
|
|
444
446
|
node.currentHUEDevice.on.on = _event.on.on;
|
|
445
447
|
}
|
|
@@ -473,24 +475,9 @@ module.exports = function (RED) {
|
|
|
473
475
|
}
|
|
474
476
|
if (_event.hasOwnProperty("color_temperature") && _event.color_temperature.mirek !== undefined) {
|
|
475
477
|
node.updateKNXLightHSVState(_event.color_temperature.mirek);
|
|
478
|
+
node.updateKNXLightKelvinState(_event.color_temperature.mirek);
|
|
476
479
|
node.currentHUEDevice.color_temperature.mirek = _event.color_temperature.mirek;
|
|
477
480
|
}
|
|
478
|
-
|
|
479
|
-
// // Update the current HUE Device with the new _event
|
|
480
|
-
// function copiaOggettoRicorsivo(objDestinazione, objOrigine) {
|
|
481
|
-
// for (const prop in objOrigine) {
|
|
482
|
-
// if (typeof objOrigine[prop] === "object" && objOrigine[prop] !== null) {
|
|
483
|
-
// // Se la proprietà è un oggetto, copiamola in modo ricorsivo
|
|
484
|
-
// objDestinazione[prop] = objDestinazione[prop] || {};
|
|
485
|
-
// copiaOggettoRicorsivo(objDestinazione[prop], objOrigine[prop]);
|
|
486
|
-
// } else {
|
|
487
|
-
// // Altrimenti, copia il valore della proprietà
|
|
488
|
-
// objDestinazione[prop] = objOrigine[prop];
|
|
489
|
-
// }
|
|
490
|
-
// }
|
|
491
|
-
// }
|
|
492
|
-
// // Copia l'oggettoOrigine nell'oggettoDestinazione mantenendo le proprietà esistenti
|
|
493
|
-
// copiaOggettoRicorsivo(node.currentHUEDevice, _event);
|
|
494
481
|
}
|
|
495
482
|
} catch (error) {
|
|
496
483
|
node.status({
|
|
@@ -617,7 +604,32 @@ module.exports = function (RED) {
|
|
|
617
604
|
}
|
|
618
605
|
};
|
|
619
606
|
|
|
620
|
-
|
|
607
|
+
node.updateKNXLightKelvinState = function updateKNXLightKelvinState(_value) {
|
|
608
|
+
if (config.GALightKelvinState !== undefined && config.GALightKelvinState !== "") {
|
|
609
|
+
const knxMsgPayload = {};
|
|
610
|
+
knxMsgPayload.topic = config.GALightKelvinState;
|
|
611
|
+
knxMsgPayload.dpt = config.dptLightKelvinState;
|
|
612
|
+
if (config.dptLightKelvinState === "7.600") {
|
|
613
|
+
knxMsgPayload.payload = hueColorConverter.ColorConverter.scale(_value, [153, 500], [0, 65535]);
|
|
614
|
+
// Send to KNX bus
|
|
615
|
+
if (knxMsgPayload.topic !== "" && knxMsgPayload.topic !== undefined) {
|
|
616
|
+
node.server.writeQueueAdd({
|
|
617
|
+
grpaddr: knxMsgPayload.topic,
|
|
618
|
+
payload: knxMsgPayload.payload,
|
|
619
|
+
dpt: knxMsgPayload.dpt,
|
|
620
|
+
outputtype: "write",
|
|
621
|
+
nodecallerid: node.id,
|
|
622
|
+
});
|
|
623
|
+
}
|
|
624
|
+
node.setNodeStatusHue({
|
|
625
|
+
fill: "blue",
|
|
626
|
+
shape: "ring",
|
|
627
|
+
text: "HUE->KNX Kelvin",
|
|
628
|
+
payload: knxMsgPayload.payload,
|
|
629
|
+
});
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
};
|
|
621
633
|
|
|
622
634
|
// On each deploy, unsubscribe+resubscribe
|
|
623
635
|
if (node.server) {
|
|
@@ -625,11 +637,39 @@ module.exports = function (RED) {
|
|
|
625
637
|
node.server.addClient(node);
|
|
626
638
|
}
|
|
627
639
|
if (node.serverHue) {
|
|
628
|
-
|
|
629
|
-
|
|
640
|
+
try {
|
|
641
|
+
node.serverHue.removeClient(node);
|
|
642
|
+
node.serverHue.addClient(node);
|
|
643
|
+
} catch (error) {
|
|
644
|
+
RED.log.error("knxUltimateHueLight: if (node.server): " + error.message);
|
|
645
|
+
}
|
|
630
646
|
}
|
|
631
647
|
|
|
632
|
-
node.on(
|
|
648
|
+
node.on('input', (msg, send, done) => {
|
|
649
|
+
try {
|
|
650
|
+
const state = RED.util.cloneMessage(msg);
|
|
651
|
+
node.serverHue.hueManager.writeHueQueueAdd(node.hueDevice, state, node.isGrouped_light === false ? "setLight" : "setGroupedLight");
|
|
652
|
+
node.setNodeStatusHue({
|
|
653
|
+
fill: "green",
|
|
654
|
+
shape: "dot",
|
|
655
|
+
text: "->HUE",
|
|
656
|
+
payload: "Flow msg.",
|
|
657
|
+
});
|
|
658
|
+
} catch (error) {
|
|
659
|
+
node.setNodeStatusHue({
|
|
660
|
+
fill: "red",
|
|
661
|
+
shape: "dot",
|
|
662
|
+
text: "->HUE",
|
|
663
|
+
payload: error.message,
|
|
664
|
+
});
|
|
665
|
+
}
|
|
666
|
+
// Once finished, call 'done'.
|
|
667
|
+
// This call is wrapped in a check that 'done' exists
|
|
668
|
+
// so the node will work in earlier versions of Node-RED (<1.0)
|
|
669
|
+
if (done) {
|
|
670
|
+
done();
|
|
671
|
+
}
|
|
672
|
+
});
|
|
633
673
|
|
|
634
674
|
node.on("close", (done) => {
|
|
635
675
|
if (node.server) {
|
|
@@ -227,7 +227,7 @@
|
|
|
227
227
|
|
|
228
228
|
|
|
229
229
|
</script>
|
|
230
|
-
<script src="
|
|
230
|
+
<script src="http://localhost:1880/resources/node-red-contrib-knx-ultimate/11f26b4500.js"></script>
|
|
231
231
|
|
|
232
232
|
<script type="text/markdown" data-help-name="knxUltimateHueLightSensor">
|
|
233
233
|
This node lets you get the events from your HUE motion device.
|
|
@@ -11,7 +11,6 @@
|
|
|
11
11
|
namemotion: { value: "" },
|
|
12
12
|
GAmotion: { value: "" },
|
|
13
13
|
dptmotion: { value: "" },
|
|
14
|
-
readStatusAtStartup: { value: "no" },
|
|
15
14
|
|
|
16
15
|
hueDevice: { value: "" }
|
|
17
16
|
},
|
|
@@ -212,21 +211,13 @@
|
|
|
212
211
|
<input type="text" id="node-input-namemotion" style="width:200px;margin-left: 5px; text-align: left;">
|
|
213
212
|
</div>
|
|
214
213
|
|
|
215
|
-
<div class="form-row">
|
|
216
|
-
<label style="width:180px" for="node-input-readStatusAtStartup"><i class="fa fa-play-circle"></i> Read status at startup</label>
|
|
217
|
-
<select id="node-input-readStatusAtStartup">
|
|
218
|
-
<option value="no">No</option>
|
|
219
|
-
<option value="yes">Yes, and emit KNX telegrams.</option>
|
|
220
|
-
</select>
|
|
221
|
-
</div>
|
|
222
|
-
|
|
223
214
|
<br/>
|
|
224
215
|
<br/>
|
|
225
216
|
<br/>
|
|
226
217
|
|
|
227
218
|
|
|
228
219
|
</script>
|
|
229
|
-
<script src="
|
|
220
|
+
<script src="http://localhost:1880/resources/node-red-contrib-knx-ultimate/11f26b4500.js"></script>
|
|
230
221
|
|
|
231
222
|
<script type="text/markdown" data-help-name="knxUltimateHueMotion">
|
|
232
223
|
This node lets you get the events from your HUE motion device.
|
|
@@ -244,7 +235,6 @@ Start typing in the GA field, the name or group address of your KNX device, the
|
|
|
244
235
|
|Property|Description|
|
|
245
236
|
|--|--|
|
|
246
237
|
| Motion | As soon as someone moves in the motion device's range, a *true* KNX value is sent to this group address, otherwise *false* is sent. |
|
|
247
|
-
| Read status at startup | Read the status at startup and emit the event to the KNX bus at startup/reconnection. (Default "no")|
|
|
248
238
|
|
|
249
239
|
### Outputs
|
|
250
240
|
|
|
@@ -42,7 +42,7 @@ module.exports = function (RED) {
|
|
|
42
42
|
if (_event.id === config.hueDevice) {
|
|
43
43
|
|
|
44
44
|
// IMPORTANT: exit if no event presen.
|
|
45
|
-
if (_event.initializingAtStart === true
|
|
45
|
+
if (_event.initializingAtStart === true) return;
|
|
46
46
|
if (!_event.hasOwnProperty("motion") || _event.motion.motion === undefined) return;
|
|
47
47
|
|
|
48
48
|
|
|
@@ -12,7 +12,10 @@
|
|
|
12
12
|
GAscene: { value: "" },
|
|
13
13
|
dptscene: { value: "" },
|
|
14
14
|
valscene: { value: 0 }, // the scene number or true/false
|
|
15
|
-
|
|
15
|
+
|
|
16
|
+
enableNodePINS: { value: "no" },
|
|
17
|
+
outputs: { value: 0 },
|
|
18
|
+
inputs: { value: 0 },
|
|
16
19
|
|
|
17
20
|
hueDevice: { value: "" },
|
|
18
21
|
hueSceneRecallType: { value: "active" }
|
|
@@ -168,7 +171,13 @@
|
|
|
168
171
|
|
|
169
172
|
},
|
|
170
173
|
oneditsave: function () {
|
|
171
|
-
|
|
174
|
+
if ($("#node-input-enableNodePINS").val() === "yes") {
|
|
175
|
+
this.outputs = 1;
|
|
176
|
+
this.inputs = 1;
|
|
177
|
+
} else {
|
|
178
|
+
this.outputs = 0;
|
|
179
|
+
this.inputs = 0;
|
|
180
|
+
}
|
|
172
181
|
|
|
173
182
|
},
|
|
174
183
|
oneditcancel: function () {
|
|
@@ -252,13 +261,21 @@
|
|
|
252
261
|
<select id="node-input-valscene" style="width:180px;margin-left: 5px; text-align: left;"></select>
|
|
253
262
|
</div>
|
|
254
263
|
|
|
264
|
+
<br/>
|
|
265
|
+
<br/>
|
|
266
|
+
|
|
267
|
+
<p>
|
|
268
|
+
<b>BEHAVIOUR</b>
|
|
269
|
+
</p>
|
|
270
|
+
|
|
255
271
|
<div class="form-row">
|
|
256
|
-
|
|
257
|
-
<
|
|
258
|
-
|
|
259
|
-
|
|
272
|
+
<label for="node-input-enableNodePINS" style="width:240px;">
|
|
273
|
+
<i class="fa fa-square-o"></i> Node Input/Output PINs
|
|
274
|
+
</label>
|
|
275
|
+
<select id="node-input-enableNodePINS">
|
|
276
|
+
<option value="no">Hide</option>
|
|
277
|
+
<option value="yes">Show node input/output PINs</option>
|
|
260
278
|
</select>
|
|
261
|
-
</div>
|
|
262
279
|
|
|
263
280
|
<br/>
|
|
264
281
|
<br/>
|
|
@@ -266,7 +283,7 @@
|
|
|
266
283
|
|
|
267
284
|
|
|
268
285
|
</script>
|
|
269
|
-
<script src="
|
|
286
|
+
<script src="http://localhost:1880/resources/node-red-contrib-knx-ultimate/11f26b4500.js"></script>
|
|
270
287
|
|
|
271
288
|
<script type="text/markdown" data-help-name="knxUltimateHueScene">
|
|
272
289
|
This node lets you recall a HUE scene, via KNX.
|
|
@@ -280,12 +297,18 @@ Start typing in the GA field, the name or group address of your KNX device, the
|
|
|
280
297
|
| HUE Bridge | Select the HUE Bridge to be used |
|
|
281
298
|
| Hue Scene | HUE scene to control. The avaiable scenes start showing up while you're typing.|
|
|
282
299
|
|
|
300
|
+
**KNX**
|
|
283
301
|
|
|
284
302
|
|Property|Description|
|
|
285
303
|
|--|--|
|
|
286
304
|
| Recall | Choose your group address to be used for recalling the HUE scene. In case of Datapoint 1.x, send *true* to that group address to recall the scene, *false* to switch off all lights belonging to the scene. |
|
|
287
305
|
| # | Select the KNX scene number. Visible only with datapoint 18.001. |
|
|
288
|
-
|
|
306
|
+
|
|
307
|
+
**BEHAVIOUR**
|
|
308
|
+
|
|
309
|
+
|Property|Description|
|
|
310
|
+
|--|--|
|
|
311
|
+
| Node Input/Output PINs | Hide or show the input/output PINs. Input/output PINS allow the node to accept msg input from the flow and send msg output to the flow. Input msg must follow the HUE API v.2 Standards. Please refer to the [official HUE Api page](https://developers.meethue.com/develop/hue-api-v2/api-reference/#resource_light__id__put) |
|
|
289
312
|
|
|
290
313
|
<br/>
|
|
291
314
|
|
|
@@ -75,31 +75,16 @@ module.exports = function (RED) {
|
|
|
75
75
|
}
|
|
76
76
|
};
|
|
77
77
|
|
|
78
|
-
node.handleSendHUE = _event => {
|
|
78
|
+
node.handleSendHUE = (_event) => {
|
|
79
79
|
try {
|
|
80
80
|
if (_event.id === config.hueDevice) {
|
|
81
81
|
|
|
82
82
|
// IMPORTANT: exit if no event presen.
|
|
83
|
-
if (_event.initializingAtStart === true
|
|
83
|
+
if (_event.initializingAtStart === true) return;
|
|
84
84
|
|
|
85
|
-
//
|
|
86
|
-
|
|
87
|
-
// knxMsgPayload.dpt = config.dptmotion
|
|
85
|
+
// Output the msg to the flow
|
|
86
|
+
node.send(_event);
|
|
88
87
|
|
|
89
|
-
// if (_event.hasOwnProperty('motion') && _event.motion.hasOwnProperty('motion')) {
|
|
90
|
-
// knxMsgPayload.payload = _event.motion.motion_report.motion
|
|
91
|
-
// // Send to KNX bus
|
|
92
|
-
// if (knxMsgPayload.topic !== '' && knxMsgPayload.topic !== undefined) node.server.writeQueueAdd({ grpaddr: knxMsgPayload.topic, payload: knxMsgPayload.payload, dpt: knxMsgPayload.dpt, outputtype: 'write', nodecallerid: node.id })
|
|
93
|
-
// node.status({ fill: 'green', shape: 'dot', text: 'HUE->KNX ' + JSON.stringify(knxMsgPayload.payload) + ' (' + new Date().getDate() + ', ' + new Date().toLocaleTimeString() + ')' })
|
|
94
|
-
|
|
95
|
-
// // Setup the output msg
|
|
96
|
-
// knxMsgPayload.name = node.name
|
|
97
|
-
// knxMsgPayload.event = 'motion'
|
|
98
|
-
|
|
99
|
-
// // Send payload
|
|
100
|
-
// knxMsgPayload.rawEvent = _event
|
|
101
|
-
// node.send(knxMsgPayload)
|
|
102
|
-
// }
|
|
103
88
|
}
|
|
104
89
|
} catch (error) {
|
|
105
90
|
node.status({ fill: 'red', shape: 'dot', text: 'HUE->KNX error ' + error.message + ' (' + new Date().getDate() + ', ' + new Date().toLocaleTimeString() + ')' });
|
|
@@ -116,10 +101,31 @@ module.exports = function (RED) {
|
|
|
116
101
|
node.serverHue.addClient(node);
|
|
117
102
|
}
|
|
118
103
|
|
|
119
|
-
node.on('input',
|
|
120
|
-
|
|
104
|
+
node.on('input', (msg, send, done) => {
|
|
105
|
+
try {
|
|
106
|
+
const state = RED.util.cloneMessage(msg);
|
|
107
|
+
node.serverHue.hueManager.writeHueQueueAdd(config.hueDevice, state, 'setScene');
|
|
108
|
+
node.setNodeStatusHue({
|
|
109
|
+
fill: "green",
|
|
110
|
+
shape: "dot",
|
|
111
|
+
text: "->HUE",
|
|
112
|
+
payload: "Flow msg.",
|
|
113
|
+
});
|
|
114
|
+
} catch (error) {
|
|
115
|
+
node.setNodeStatusHue({
|
|
116
|
+
fill: "red",
|
|
117
|
+
shape: "dot",
|
|
118
|
+
text: "->HUE",
|
|
119
|
+
payload: error.message,
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
// Once finished, call 'done'.
|
|
123
|
+
// This call is wrapped in a check that 'done' exists
|
|
124
|
+
// so the node will work in earlier versions of Node-RED (<1.0)
|
|
125
|
+
if (done) {
|
|
126
|
+
done();
|
|
127
|
+
}
|
|
121
128
|
});
|
|
122
|
-
|
|
123
129
|
node.on('close', function (done) {
|
|
124
130
|
if (node.server) {
|
|
125
131
|
node.server.removeClient(node);
|
|
@@ -11,7 +11,6 @@
|
|
|
11
11
|
namerepeat: { value: "" },
|
|
12
12
|
GArepeat: { value: "" },
|
|
13
13
|
dptrepeat: { value: "" },
|
|
14
|
-
readStatusAtStartup: { value: "no" },
|
|
15
14
|
|
|
16
15
|
hueDevice: { value: "" }
|
|
17
16
|
},
|
|
@@ -214,23 +213,13 @@
|
|
|
214
213
|
<input type="text" id="node-input-namerepeat" style="width:200px;margin-left: 5px; text-align: left;">
|
|
215
214
|
</div>
|
|
216
215
|
|
|
217
|
-
|
|
218
|
-
<div class="form-row">
|
|
219
|
-
<label style="width:180px" for="node-input-readStatusAtStartup"><i class="fa fa-play-circle"></i> Read status at startup</label>
|
|
220
|
-
<select id="node-input-readStatusAtStartup">
|
|
221
|
-
<option value="no">No</option>
|
|
222
|
-
<option value="yes">Yes, and emit KNX telegrams.</option>
|
|
223
|
-
</select>
|
|
224
|
-
</div>
|
|
225
|
-
|
|
226
|
-
|
|
227
216
|
<br/>
|
|
228
217
|
<br/>
|
|
229
218
|
<br/>
|
|
230
219
|
|
|
231
220
|
|
|
232
221
|
</script>
|
|
233
|
-
<script src="
|
|
222
|
+
<script src="http://localhost:1880/resources/node-red-contrib-knx-ultimate/11f26b4500.js"></script>
|
|
234
223
|
|
|
235
224
|
<script type="text/markdown" data-help-name="knxUltimateHueTapDial">
|
|
236
225
|
This node lets you get the events from your HUE rotary device, for example the Tap Dial.
|
|
@@ -252,7 +241,6 @@ or a random color (Datapoint 232.600) to the selected group address.
|
|
|
252
241
|
|Property|Description|
|
|
253
242
|
|--|--|
|
|
254
243
|
| Rotate | This command is used either to send DIM (increase/decrease), aboslute brightness, or a random color, depending on the selected datapoint. If the random color (datapoint 232.600) is selected, **clockwise rotation** changes random colors and **counterclockwise rotation** set the light to **white** |
|
|
255
|
-
| Read status at startup | Read the status at startup and emit the event to the KNX bus at startup/reconnection. (Default "no")|
|
|
256
244
|
|
|
257
245
|
### Outputs
|
|
258
246
|
|
|
@@ -51,7 +51,7 @@ module.exports = function (RED) {
|
|
|
51
51
|
if (_event.id === config.hueDevice) {
|
|
52
52
|
|
|
53
53
|
// IMPORTANT: exit if no event presen.
|
|
54
|
-
if (_event.initializingAtStart === true
|
|
54
|
+
if (_event.initializingAtStart === true) return;
|
|
55
55
|
if (!_event.hasOwnProperty("relative_rotary")
|
|
56
56
|
|| !_event.relative_rotary.hasOwnProperty("last_event")
|
|
57
57
|
|| _event.relative_rotary.last_event === undefined
|
|
@@ -218,13 +218,13 @@
|
|
|
218
218
|
|
|
219
219
|
|
|
220
220
|
</script>
|
|
221
|
-
<script src="
|
|
221
|
+
<script src="http://localhost:1880/resources/node-red-contrib-knx-ultimate/11f26b4500.js"></script>
|
|
222
222
|
|
|
223
|
-
<script type="text/markdown" data-help-name="knxUltimateHueTemperatureSensor"
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
223
|
+
<script type="text/markdown" data-help-name="knxUltimateHueTemperatureSensor" This node lets you get the events from
|
|
224
|
+
your HUE temperature device. Here you can get the HUE temperature events, that represents a celsius value, evetytime
|
|
225
|
+
the ambient temp changes.<br />
|
|
226
|
+
Start typing in the GA field, the name or group address of your KNX device, the avaiable devices start showing up while
|
|
227
|
+
you're typing.
|
|
228
228
|
|
|
229
229
|
**General**
|
|
230
230
|
|Property|Description|
|
|
@@ -245,13 +245,13 @@ Start typing in the GA field, the name or group address of your KNX device, the
|
|
|
245
245
|
|
|
246
246
|
### Details
|
|
247
247
|
|
|
248
|
-
`msg.payload` is used as the payload of the published message.
|
|
249
|
-
It contains the detailed event sent by your Hue devicem so you can use it for whatever you want.
|
|
248
|
+
`msg.payload` is used as the payload of the published message.
|
|
249
|
+
It contains the detailed event sent by your Hue devicem so you can use it for whatever you want.
|
|
250
250
|
|
|
251
|
-
<br/>
|
|
251
|
+
<br />
|
|
252
252
|
|
|
253
253
|
[Find it useful?](https://www.paypal.me/techtoday)
|
|
254
254
|
|
|
255
|
-
<br/>
|
|
255
|
+
<br />
|
|
256
256
|
|
|
257
|
-
|
|
257
|
+
</script>
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
|
|
2
1
|
module.exports = function (RED) {
|
|
3
|
-
function knxUltimateSceneController
|
|
2
|
+
function knxUltimateSceneController(config) {
|
|
4
3
|
const fs = require('fs')
|
|
5
4
|
const path = require('path')
|
|
6
5
|
const mkdirp = require('mkdirp')
|
|
@@ -43,7 +42,7 @@ module.exports = function (RED) {
|
|
|
43
42
|
})
|
|
44
43
|
|
|
45
44
|
// 03/09/2021
|
|
46
|
-
async function delay
|
|
45
|
+
async function delay(ms) {
|
|
47
46
|
return new Promise(function (resolve, reject) {
|
|
48
47
|
try {
|
|
49
48
|
node.timerWait = setTimeout(resolve, ms)
|
|
@@ -53,7 +52,7 @@ module.exports = function (RED) {
|
|
|
53
52
|
})
|
|
54
53
|
}
|
|
55
54
|
|
|
56
|
-
function setupDirectory
|
|
55
|
+
function setupDirectory(aPath) {
|
|
57
56
|
try {
|
|
58
57
|
return fs.statSync(aPath).isDirectory()
|
|
59
58
|
} catch (e) {
|
|
@@ -115,7 +114,7 @@ module.exports = function (RED) {
|
|
|
115
114
|
}
|
|
116
115
|
|
|
117
116
|
// 03/09/2021 Async function to allow await delay(x)
|
|
118
|
-
async function RecallSceneAsync
|
|
117
|
+
async function RecallSceneAsync(_Payload, _ForceEvenControllerIsDisabled) {
|
|
119
118
|
let curVal
|
|
120
119
|
var newVal
|
|
121
120
|
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"engines": {
|
|
4
4
|
"node": ">=16.0.0"
|
|
5
5
|
},
|
|
6
|
-
"version": "2.2.
|
|
6
|
+
"version": "2.2.10",
|
|
7
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",
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
window.FontAwesomeKitConfig = { "asyncLoading": { "enabled": false }, "autoA11y": { "enabled": true }, "baseUrl": "https://ka-f.fontawesome.com", "baseUrlKit": "https://kit.fontawesome.com", "detectConflictsUntil": null, "iconUploads": {}, "id": 2836081, "license": "free", "method": "css", "minify": { "enabled": true }, "token": "11f26b4500", "v4FontFaceShim": { "enabled": true }, "v4shim": { "enabled": true }, "v5FontFaceShim": { "enabled": true }, "version": "6.4.2" };
|
|
2
|
+
!function (t) { "function" == typeof define && define.amd ? define("kit-loader", t) : t() }((function () { "use strict"; function t(t, e) { var n = Object.keys(t); if (Object.getOwnPropertySymbols) { var r = Object.getOwnPropertySymbols(t); e && (r = r.filter((function (e) { return Object.getOwnPropertyDescriptor(t, e).enumerable }))), n.push.apply(n, r) } return n } function e(e) { for (var n = 1; n < arguments.length; n++) { var o = null != arguments[n] ? arguments[n] : {}; n % 2 ? t(Object(o), !0).forEach((function (t) { r(e, t, o[t]) })) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(o)) : t(Object(o)).forEach((function (t) { Object.defineProperty(e, t, Object.getOwnPropertyDescriptor(o, t)) })) } return e } function n(t) { return (n = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (t) { return typeof t } : function (t) { return t && "function" == typeof Symbol && t.constructor === Symbol && t !== Symbol.prototype ? "symbol" : typeof t })(t) } function r(t, e, n) { return (e = function (t) { var e = function (t, e) { if ("object" != typeof t || null === t) return t; var n = t[Symbol.toPrimitive]; if (void 0 !== n) { var r = n.call(t, e || "default"); if ("object" != typeof r) return r; throw new TypeError("@@toPrimitive must return a primitive value.") } return ("string" === e ? String : Number)(t) }(t, "string"); return "symbol" == typeof e ? e : String(e) }(e)) in t ? Object.defineProperty(t, e, { value: n, enumerable: !0, configurable: !0, writable: !0 }) : t[e] = n, t } function o(t, e) { return function (t) { if (Array.isArray(t)) return t }(t) || function (t, e) { var n = null == t ? null : "undefined" != typeof Symbol && t[Symbol.iterator] || t["@@iterator"]; if (null != n) { var r, o, i, c, a = [], u = !0, f = !1; try { if (i = (n = n.call(t)).next, 0 === e) { if (Object(n) !== n) return; u = !1 } else for (; !(u = (r = i.call(n)).done) && (a.push(r.value), a.length !== e); u = !0); } catch (t) { f = !0, o = t } finally { try { if (!u && null != n.return && (c = n.return(), Object(c) !== c)) return } finally { if (f) throw o } } return a } }(t, e) || function (t, e) { if (!t) return; if ("string" == typeof t) return i(t, e); var n = Object.prototype.toString.call(t).slice(8, -1); "Object" === n && t.constructor && (n = t.constructor.name); if ("Map" === n || "Set" === n) return Array.from(t); if ("Arguments" === n || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return i(t, e) }(t, e) || function () { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.") }() } function i(t, e) { (null == e || e > t.length) && (e = t.length); for (var n = 0, r = new Array(e); n < e; n++)r[n] = t[n]; return r } function c(t, e) { var n = e && e.addOn || "", r = e && e.baseFilename || t.license + n, o = e && e.minify ? ".min" : "", i = e && e.fileSuffix || t.method, c = e && e.subdir || t.method; return t.baseUrl + "/releases/" + ("latest" === t.version ? "latest" : "v".concat(t.version)) + "/" + c + "/" + r + o + "." + i } function a(t, e) { var n = e || ["fa"], r = "." + Array.prototype.join.call(n, ",."), o = t.querySelectorAll(r); Array.prototype.forEach.call(o, (function (e) { var n = e.getAttribute("title"); e.setAttribute("aria-hidden", "true"); var r = !e.nextElementSibling || !e.nextElementSibling.classList.contains("sr-only"); if (n && r) { var o = t.createElement("span"); o.innerHTML = n, o.classList.add("sr-only"), e.parentNode.insertBefore(o, e.nextSibling) } })) } var u, f = function () { }, s = "undefined" != typeof global && void 0 !== global.process && "function" == typeof global.process.emit, l = "undefined" == typeof setImmediate ? setTimeout : setImmediate, d = []; function h() { for (var t = 0; t < d.length; t++)d[t][0](d[t][1]); d = [], u = !1 } function m(t, e) { d.push([t, e]), u || (u = !0, l(h, 0)) } function p(t) { var e = t.owner, n = e._state, r = e._data, o = t[n], i = t.then; if ("function" == typeof o) { n = "fulfilled"; try { r = o(r) } catch (t) { g(i, t) } } v(i, r) || ("fulfilled" === n && b(i, r), "rejected" === n && g(i, r)) } function v(t, e) { var r; try { if (t === e) throw new TypeError("A promises callback cannot return that same promise."); if (e && ("function" == typeof e || "object" === n(e))) { var o = e.then; if ("function" == typeof o) return o.call(e, (function (n) { r || (r = !0, e === n ? y(t, n) : b(t, n)) }), (function (e) { r || (r = !0, g(t, e)) })), !0 } } catch (e) { return r || g(t, e), !0 } return !1 } function b(t, e) { t !== e && v(t, e) || y(t, e) } function y(t, e) { "pending" === t._state && (t._state = "settled", t._data = e, m(A, t)) } function g(t, e) { "pending" === t._state && (t._state = "settled", t._data = e, m(S, t)) } function w(t) { t._then = t._then.forEach(p) } function A(t) { t._state = "fulfilled", w(t) } function S(t) { t._state = "rejected", w(t), !t._handled && s && global.process.emit("unhandledRejection", t._data, t) } function O(t) { global.process.emit("rejectionHandled", t) } function j(t) { if ("function" != typeof t) throw new TypeError("Promise resolver " + t + " is not a function"); if (this instanceof j == !1) throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function."); this._then = [], function (t, e) { function n(t) { g(e, t) } try { t((function (t) { b(e, t) }), n) } catch (t) { n(t) } }(t, this) } j.prototype = { constructor: j, _state: "pending", _then: null, _data: void 0, _handled: !1, then: function (t, e) { var n = { owner: this, then: new this.constructor(f), fulfilled: t, rejected: e }; return !e && !t || this._handled || (this._handled = !0, "rejected" === this._state && s && m(O, this)), "fulfilled" === this._state || "rejected" === this._state ? m(p, n) : this._then.push(n), n.then }, catch: function (t) { return this.then(null, t) } }, j.all = function (t) { if (!Array.isArray(t)) throw new TypeError("You must pass an array to Promise.all()."); return new j((function (e, n) { var r = [], o = 0; function i(t) { return o++, function (n) { r[t] = n, --o || e(r) } } for (var c, a = 0; a < t.length; a++)(c = t[a]) && "function" == typeof c.then ? c.then(i(a), n) : r[a] = c; o || e(r) })) }, j.race = function (t) { if (!Array.isArray(t)) throw new TypeError("You must pass an array to Promise.race()."); return new j((function (e, n) { for (var r, o = 0; o < t.length; o++)(r = t[o]) && "function" == typeof r.then ? r.then(e, n) : e(r) })) }, j.resolve = function (t) { return t && "object" === n(t) && t.constructor === j ? t : new j((function (e) { e(t) })) }, j.reject = function (t) { return new j((function (e, n) { n(t) })) }; var E = "function" == typeof Promise ? Promise : j; function P(t, e) { var n = e.fetch, r = e.XMLHttpRequest, o = e.token, i = t; return o && !function (t) { return t.indexOf("kit-upload.css") > -1 }(t) && ("URLSearchParams" in window ? (i = new URL(t)).searchParams.set("token", o) : i = i + "?token=" + encodeURIComponent(o)), i = i.toString(), new E((function (t, e) { if ("function" == typeof n) n(i, { mode: "cors", cache: "default" }).then((function (t) { if (t.ok) return t.text(); throw new Error("") })).then((function (e) { t(e) })).catch(e); else if ("function" == typeof r) { var o = new r; o.addEventListener("loadend", (function () { this.responseText ? t(this.responseText) : e(new Error("")) }));["abort", "error", "timeout"].map((function (t) { o.addEventListener(t, (function () { e(new Error("")) })) })), o.open("GET", i), o.send() } else { e(new Error("")) } })) } function _(t, e, n) { var r = t; return [[/(url\("?)\.\.\/\.\.\/\.\./g, function (t, n) { return "".concat(n).concat(e) }], [/(url\("?)\.\.\/webfonts/g, function (t, r) { return "".concat(r).concat(e, "/releases/v").concat(n, "/webfonts") }], [/(url\("?)https:\/\/kit-free([^.])*\.fontawesome\.com/g, function (t, n) { return "".concat(n).concat(e) }]].forEach((function (t) { var e = o(t, 2), n = e[0], i = e[1]; r = r.replace(n, i) })), r } function F(t, n) { var r = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : function () { }, o = n.document || o, i = a.bind(a, o, ["fa", "fab", "fas", "far", "fal", "fad", "fak"]); t.autoA11y.enabled && r(i); var u = t.subsetPath && t.baseUrl + "/" + t.subsetPath, f = [{ id: "fa-main", addOn: void 0, url: u }]; if (t.v4shim && t.v4shim.enabled && f.push({ id: "fa-v4-shims", addOn: "-v4-shims" }), t.v5FontFaceShim && t.v5FontFaceShim.enabled && f.push({ id: "fa-v5-font-face", addOn: "-v5-font-face" }), t.v4FontFaceShim && t.v4FontFaceShim.enabled && f.push({ id: "fa-v4-font-face", addOn: "-v4-font-face" }), !u && t.customIconsCssPath) { var s = t.customIconsCssPath.indexOf("kit-upload.css") > -1 ? t.baseUrlKit : t.baseUrl, l = s + "/" + t.customIconsCssPath; f.push({ id: "fa-kit-upload", url: l }) } var d = f.map((function (r) { return new E((function (o, i) { var a = r.url || c(t, { addOn: r.addOn, minify: t.minify.enabled }), u = { id: r.id }, f = t.subset ? u : e(e(e({}, n), u), {}, { baseUrl: t.baseUrl, version: t.version, id: r.id, contentFilter: function (t, e) { return _(t, e.baseUrl, e.version) } }); P(a, n).then((function (t) { o(C(t, f)) })).catch(i) })) })); return E.all(d) } function C(t, e) { var n = e.contentFilter || function (t, e) { return t }, r = document.createElement("style"), o = document.createTextNode(n(t, e)); return r.appendChild(o), r.media = "all", e.id && r.setAttribute("id", e.id), e && e.detectingConflicts && e.detectionIgnoreAttr && r.setAttributeNode(document.createAttribute(e.detectionIgnoreAttr)), r } function I(t, n) { n.autoA11y = t.autoA11y.enabled, "pro" === t.license && (n.autoFetchSvg = !0, n.fetchSvgFrom = t.baseUrl + "/releases/" + ("latest" === t.version ? "latest" : "v".concat(t.version)) + "/svgs", n.fetchUploadedSvgFrom = t.uploadsUrl); var r = []; return t.v4shim.enabled && r.push(new E((function (r, o) { P(c(t, { addOn: "-v4-shims", minify: t.minify.enabled }), n).then((function (t) { r(U(t, e(e({}, n), {}, { id: "fa-v4-shims" }))) })).catch(o) }))), r.push(new E((function (r, o) { P(t.subsetPath && t.baseUrl + "/" + t.subsetPath || c(t, { minify: t.minify.enabled }), n).then((function (t) { var o = U(t, e(e({}, n), {}, { id: "fa-main" })); r(function (t, e) { var n = e && void 0 !== e.autoFetchSvg ? e.autoFetchSvg : void 0, r = e && void 0 !== e.autoA11y ? e.autoA11y : void 0; void 0 !== r && t.setAttribute("data-auto-a11y", r ? "true" : "false"); n && (t.setAttributeNode(document.createAttribute("data-auto-fetch-svg")), t.setAttribute("data-fetch-svg-from", e.fetchSvgFrom), t.setAttribute("data-fetch-uploaded-svg-from", e.fetchUploadedSvgFrom)); return t }(o, n)) })).catch(o) }))), E.all(r) } function U(t, e) { var n = document.createElement("SCRIPT"), r = document.createTextNode(t); return n.appendChild(r), n.referrerPolicy = "strict-origin", e.id && n.setAttribute("id", e.id), e && e.detectingConflicts && e.detectionIgnoreAttr && n.setAttributeNode(document.createAttribute(e.detectionIgnoreAttr)), n } function T(t) { var e, n = [], r = document, o = r.documentElement.doScroll, i = (o ? /^loaded|^c/ : /^loaded|^i|^c/).test(r.readyState); i || r.addEventListener("DOMContentLoaded", e = function () { for (r.removeEventListener("DOMContentLoaded", e), i = 1; e = n.shift();)e() }), i ? setTimeout(t, 0) : n.push(t) } function L(t) { "undefined" != typeof MutationObserver && new MutationObserver(t).observe(document, { childList: !0, subtree: !0 }) } try { if (window.FontAwesomeKitConfig) { var k = window.FontAwesomeKitConfig, x = { detectingConflicts: k.detectConflictsUntil && new Date <= new Date(k.detectConflictsUntil), detectionIgnoreAttr: "data-fa-detection-ignore", fetch: window.fetch, token: k.token, XMLHttpRequest: window.XMLHttpRequest, document: document }, M = document.currentScript, N = M ? M.parentElement : document.head; (function () { var t = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, e = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}; return "js" === t.method ? I(t, e) : "css" === t.method ? F(t, e, (function (t) { T(t), L(t) })) : void 0 })(k, x).then((function (t) { t.map((function (t) { try { N.insertBefore(t, M ? M.nextSibling : null) } catch (e) { N.appendChild(t) } })), x.detectingConflicts && M && T((function () { M.setAttributeNode(document.createAttribute(x.detectionIgnoreAttr)); var t = function (t, e) { var n = document.createElement("script"); return e && e.detectionIgnoreAttr && n.setAttributeNode(document.createAttribute(e.detectionIgnoreAttr)), n.src = c(t, { baseFilename: "conflict-detection", fileSuffix: "js", subdir: "js", minify: t.minify.enabled }), n }(k, x); document.body.appendChild(t) })) })).catch((function (t) { console.error("".concat("Font Awesome Kit:", " ").concat(t)) })) } } catch (t) { console.error("".concat("Font Awesome Kit:", " ").concat(t)) } }));
|