node-red-contrib-knx-ultimate 2.1.13 → 2.1.15
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 +8 -0
- package/nodes/hue-config.html +44 -36
- package/nodes/hue-config.js +7 -4
- package/nodes/knxUltimate-config.js +32 -27
- package/nodes/knxUltimateHueLight.html +84 -1
- package/nodes/knxUltimateHueLight.js +18 -1
- package/nodes/utils/hueUtils.js +4 -4
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,14 @@
|
|
|
6
6
|
|
|
7
7
|
# CHANGELOG
|
|
8
8
|
|
|
9
|
+
<p>
|
|
10
|
+
<b>Version 2.1.15</b> - June 2023<br/>
|
|
11
|
+
- Fix an issue with auto discovery of not registered HUE bridges. Now you must first set the IP, then click CONNECT.<br/>
|
|
12
|
+
</p>
|
|
13
|
+
<p>
|
|
14
|
+
<b>Version 2.1.14</b> - June 2023<br/>
|
|
15
|
+
- Hue Light node: added day/night behaviour.<br/>
|
|
16
|
+
</p>
|
|
9
17
|
<p>
|
|
10
18
|
<b>Version 2.1.13</b> - June 2023<br/>
|
|
11
19
|
- Hue Light node: fixed inversion in the color temp state.<br/>
|
package/nodes/hue-config.html
CHANGED
|
@@ -11,8 +11,11 @@
|
|
|
11
11
|
clientkey: { type: "password" }
|
|
12
12
|
},
|
|
13
13
|
oneditprepare: function () {
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
if (this.bridgeid === undefined || this.bridgeid === '') {
|
|
15
|
+
$("#divDetails").hide()
|
|
16
|
+
} else {
|
|
17
|
+
$("#divDetails").show()
|
|
18
|
+
}
|
|
16
19
|
$("#getinfocam").click(function () {
|
|
17
20
|
|
|
18
21
|
var myNotification = RED.notify("Please press the Link button on the HUE Bridge / Pre favore, premi il pulsante sul bridge HUE",
|
|
@@ -25,7 +28,7 @@
|
|
|
25
28
|
text: "OK",
|
|
26
29
|
click: function (e) {
|
|
27
30
|
// Send the infos to Supergiovane
|
|
28
|
-
$.getJSON("KNXUltimateRegisterToHueBridge", (data) => {
|
|
31
|
+
$.getJSON("KNXUltimateRegisterToHueBridge?IP=" + $("#node-config-input-host").val(), (data) => {
|
|
29
32
|
this.value = "Connect";
|
|
30
33
|
this.disabled = false;
|
|
31
34
|
if (data.hasOwnProperty("error")) {
|
|
@@ -35,16 +38,18 @@
|
|
|
35
38
|
fixed: false,
|
|
36
39
|
type: 'error'
|
|
37
40
|
});
|
|
38
|
-
this.disabled =
|
|
41
|
+
this.disabled = false;
|
|
42
|
+
$("#divDetails").hide()
|
|
39
43
|
return;
|
|
40
44
|
}
|
|
41
45
|
|
|
42
46
|
// Expected { bridge: bridgeConfig, user: createdUser }
|
|
43
47
|
$("#node-config-input-name").val(data.bridge.data.name);
|
|
44
|
-
$("#node-config-input-host").val(data.bridge.data.ipaddress);
|
|
48
|
+
// $("#node-config-input-host").val(data.bridge.data.ipaddress);
|
|
45
49
|
$("#node-config-input-username").val(data.user.username);
|
|
46
50
|
$("#node-config-input-clientkey").val(data.user.clientkey);
|
|
47
51
|
$("#node-config-input-bridgeid").val(data.bridge.data.bridgeid);
|
|
52
|
+
$("#divDetails").show()
|
|
48
53
|
|
|
49
54
|
}).error(function (jqXHR, textStatus, errorThrown) {
|
|
50
55
|
RED.notify("Something went wrong. Please create at least a KNX Gateway node first.",
|
|
@@ -88,51 +93,54 @@
|
|
|
88
93
|
|
|
89
94
|
<p align='center'> <img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-knx-ultimate/master/img/huehub.jpg' width='40%'></p>
|
|
90
95
|
|
|
91
|
-
|
|
92
|
-
<div class="form-row">
|
|
93
|
-
<label><i class="fa fa-sign-in"></i> Register</label>
|
|
94
|
-
<input type="button" id="getinfocam" class="ui-button ui-corner-all ui-widget" style="background-color:#AEE1FF;width:150px" value="CONNECT">
|
|
95
|
-
</div>
|
|
96
|
-
|
|
97
|
-
<div class="form-row">
|
|
98
|
-
<label for="node-config-input-name">
|
|
99
|
-
<i class="fa fa-tag"></i>
|
|
100
|
-
<span data-i18n="hue-config.properties.node-config-input-name"</span>
|
|
101
|
-
</label>
|
|
102
|
-
<input type="text" id="node-config-input-name" ><data-i18n="[Title]hue-config.properties.node-config-input-name" style="margin-left:5px;">
|
|
103
|
-
</div>
|
|
104
|
-
|
|
105
|
-
<div class="form-row">
|
|
106
|
-
<label for="node-config-input-bridgeid">
|
|
107
|
-
<i class="fa fa-tag"></i>
|
|
108
|
-
Bridge ID
|
|
109
|
-
</label>
|
|
110
|
-
<input type="text" id="node-config-input-bridgeid" disabled>
|
|
111
|
-
</div>
|
|
112
|
-
|
|
96
|
+
|
|
113
97
|
<div class="form-row">
|
|
114
98
|
<label for="node-config-input-host">
|
|
115
99
|
<i class="fa fa-server"></i>
|
|
116
|
-
<span data-i18n="hue-config.properties.host"</span>
|
|
100
|
+
<span data-i18n="hue-config.properties.host" </span>
|
|
117
101
|
</label>
|
|
118
|
-
<input type="text" id="node-config-input-host"
|
|
102
|
+
<input type="text" id="node-config-input-host" placeholder="Write here the HUE bridge's IP, then click CONNECT">
|
|
119
103
|
</div>
|
|
120
104
|
<div class="form-row">
|
|
121
|
-
<label
|
|
122
|
-
<input type="
|
|
123
|
-
|
|
124
|
-
<div class="form-row">
|
|
125
|
-
<label for="node-config-input-clientkey"> Bridge Key</label>
|
|
126
|
-
<input type="password" id="node-config-input-clientkey" placeholder="">
|
|
105
|
+
<label><i class="fa fa-sign-in"></i> Register</label>
|
|
106
|
+
<input type="button" id="getinfocam" class="ui-button ui-corner-all ui-widget"
|
|
107
|
+
style="background-color:#AEE1FF;width:150px" value="CONNECT">
|
|
127
108
|
</div>
|
|
109
|
+
|
|
110
|
+
<div id="divDetails" hidden>
|
|
111
|
+
<div class="form-row">
|
|
112
|
+
<label for="node-config-input-name">
|
|
113
|
+
<i class="fa fa-tag"></i>
|
|
114
|
+
<span data-i18n="hue-config.properties.node-config-input-name" </span>
|
|
115
|
+
</label>
|
|
116
|
+
<input type="text" id="node-config-input-name"><data-i18n="[Title]hue-config.properties.node-config-input-name"
|
|
117
|
+
style="margin-left:5px;">
|
|
118
|
+
</div>
|
|
128
119
|
|
|
120
|
+
<div class="form-row">
|
|
121
|
+
<label for="node-config-input-bridgeid">
|
|
122
|
+
<i class="fa fa-tag"></i>
|
|
123
|
+
Bridge ID
|
|
124
|
+
</label>
|
|
125
|
+
<input type="text" id="node-config-input-bridgeid" disabled>
|
|
126
|
+
</div>
|
|
127
|
+
|
|
128
|
+
<div class="form-row">
|
|
129
|
+
<label for="node-config-input-username"> Username</label>
|
|
130
|
+
<input type="password" id="node-config-input-username" placeholder="">
|
|
131
|
+
</div>
|
|
132
|
+
<div class="form-row">
|
|
133
|
+
<label for="node-config-input-clientkey"> Bridge Key</label>
|
|
134
|
+
<input type="password" id="node-config-input-clientkey" placeholder="">
|
|
135
|
+
</div>
|
|
136
|
+
</div>
|
|
129
137
|
|
|
130
138
|
|
|
131
139
|
</script>
|
|
132
140
|
<script type="text/html" data-help-name="hue-config">
|
|
133
141
|
<p> This node registers to the Hue Bridge.<br/>
|
|
134
142
|
|
|
135
|
-
Just click **
|
|
143
|
+
Just set the Bridge's ip and click **CONNECT** button.
|
|
136
144
|
|
|
137
145
|
[Find it useful?](https://www.paypal.me/techtoday)
|
|
138
146
|
|
package/nodes/hue-config.js
CHANGED
|
@@ -51,7 +51,7 @@ module.exports = (RED) => {
|
|
|
51
51
|
res.json(dpts)
|
|
52
52
|
})
|
|
53
53
|
|
|
54
|
-
function hueConfig
|
|
54
|
+
function hueConfig(config) {
|
|
55
55
|
RED.nodes.createNode(this, config)
|
|
56
56
|
const node = this
|
|
57
57
|
node.host = config.host
|
|
@@ -124,9 +124,12 @@ module.exports = (RED) => {
|
|
|
124
124
|
node.nodeClients = []
|
|
125
125
|
node.hueManager.removeAllListeners();
|
|
126
126
|
(async () => {
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
127
|
+
try {
|
|
128
|
+
await node.hueManager.close()
|
|
129
|
+
node.hueManager = null
|
|
130
|
+
delete node.hueManager
|
|
131
|
+
} catch (error) {
|
|
132
|
+
}
|
|
130
133
|
done()
|
|
131
134
|
})()
|
|
132
135
|
} catch (error) {
|
|
@@ -99,7 +99,7 @@ return msg;`,
|
|
|
99
99
|
res.json(jRet)
|
|
100
100
|
})
|
|
101
101
|
|
|
102
|
-
function knxUltimateConfigNode
|
|
102
|
+
function knxUltimateConfigNode(config) {
|
|
103
103
|
RED.nodes.createNode(this, config)
|
|
104
104
|
const node = this
|
|
105
105
|
node.host = config.host
|
|
@@ -170,7 +170,7 @@ return msg;`,
|
|
|
170
170
|
}
|
|
171
171
|
|
|
172
172
|
node.setAllClientsStatus = (_status, _color, _text) => {
|
|
173
|
-
function nextStatus
|
|
173
|
+
function nextStatus(_oClient) {
|
|
174
174
|
let oClient = RED.nodes.getNode(_oClient.id)
|
|
175
175
|
oClient.setNodeStatus({ fill: _color, shape: 'dot', text: _status + ' ' + _text, payload: '', GA: oClient.topic, dpt: '', devicename: '' })
|
|
176
176
|
oClient = null
|
|
@@ -216,7 +216,7 @@ return msg;`,
|
|
|
216
216
|
// 04/04/2021 Supergiovane, creates the service paths where the persistent files are created.
|
|
217
217
|
// The values file is stored only upon disconnection/close
|
|
218
218
|
// ************************
|
|
219
|
-
function setupDirectory
|
|
219
|
+
function setupDirectory(_aPath) {
|
|
220
220
|
if (!fs.existsSync(_aPath)) {
|
|
221
221
|
// Create the path
|
|
222
222
|
try {
|
|
@@ -236,7 +236,7 @@ return msg;`,
|
|
|
236
236
|
if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.info('KNXUltimate-config: payload cache set to ' + path.join(node.userDir, 'knxpersistvalues'))
|
|
237
237
|
}
|
|
238
238
|
|
|
239
|
-
function saveExposedGAs
|
|
239
|
+
function saveExposedGAs() {
|
|
240
240
|
const sFile = path.join(node.userDir, 'knxpersistvalues', 'knxpersist' + node.id + '.json')
|
|
241
241
|
try {
|
|
242
242
|
if (node.exposedGAs.length > 0) {
|
|
@@ -247,7 +247,7 @@ return msg;`,
|
|
|
247
247
|
if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.error('KNXUltimate-config: unable to write peristent values to the file ' + sFile + ' ' + err.message)
|
|
248
248
|
}
|
|
249
249
|
}
|
|
250
|
-
function loadExposedGAs
|
|
250
|
+
function loadExposedGAs() {
|
|
251
251
|
const sFile = path.join(node.userDir, 'knxpersistvalues', 'knxpersist' + node.id + '.json')
|
|
252
252
|
try {
|
|
253
253
|
node.exposedGAs = JSON.parse(fs.readFileSync(sFile, 'utf8'))
|
|
@@ -262,6 +262,10 @@ return msg;`,
|
|
|
262
262
|
// Endpoint for connecting to HUE Bridge
|
|
263
263
|
RED.httpAdmin.get('/KNXUltimateRegisterToHueBridge', RED.auth.needsPermission('knxUltimate-config.read'), function (req, res) {
|
|
264
264
|
try {
|
|
265
|
+
if (typeof req.query.nodeID !== 'undefined' && req.query.nodeID !== null && req.query.nodeID !== '') {
|
|
266
|
+
const _node = RED.nodes.getNode(req.query.nodeID)// Retrieve node.id of the config node.
|
|
267
|
+
if (_node !== null) res.json(RED.nodes.getNode(_node.id).csv)
|
|
268
|
+
}
|
|
265
269
|
(async () => {
|
|
266
270
|
try {
|
|
267
271
|
// °°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°
|
|
@@ -272,20 +276,21 @@ return msg;`,
|
|
|
272
276
|
const appName = 'KNXUltimate'
|
|
273
277
|
const deviceName = 'Node-Red'
|
|
274
278
|
|
|
275
|
-
async function discoverBridge
|
|
276
|
-
|
|
279
|
+
// async function discoverBridge() {
|
|
280
|
+
// const discoveryResults = await discovery.nupnpSearch()
|
|
277
281
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
}
|
|
282
|
+
// if (discoveryResults.length === 0) {
|
|
283
|
+
// if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.error('Failed to resolve any Hue Bridges')
|
|
284
|
+
// return null
|
|
285
|
+
// } else {
|
|
286
|
+
// // Ignoring that you could have more than one Hue Bridge on a network as this is unlikely in 99.9% of users situations
|
|
287
|
+
// return discoveryResults[0].ipaddress
|
|
288
|
+
// }
|
|
289
|
+
// }
|
|
286
290
|
|
|
287
|
-
async function discoverAndCreateUser
|
|
288
|
-
const ipAddress = await discoverBridge()
|
|
291
|
+
async function discoverAndCreateUser() {
|
|
292
|
+
// const ipAddress = await discoverBridge()
|
|
293
|
+
const ipAddress = req.query.IP
|
|
289
294
|
|
|
290
295
|
// Create an unauthenticated instance of the Hue API so that we can create a new user
|
|
291
296
|
const unauthenticatedApi = await hueApi.createLocal(ipAddress).connect()
|
|
@@ -533,7 +538,7 @@ return msg;`,
|
|
|
533
538
|
}
|
|
534
539
|
|
|
535
540
|
// 17/02/2020 Do initial read (called by node.timerDoInitialRead timer)
|
|
536
|
-
function DoInitialReadFromKNXBusOrFile
|
|
541
|
+
function DoInitialReadFromKNXBusOrFile() {
|
|
537
542
|
if (node.linkStatus !== 'connected') return // 29/08/2019 If not connected, exit
|
|
538
543
|
loadExposedGAs() // 04/04/2021 load the current values of GA payload
|
|
539
544
|
try {
|
|
@@ -893,7 +898,7 @@ return msg;`,
|
|
|
893
898
|
|
|
894
899
|
// Handle BUS events
|
|
895
900
|
// ---------------------------------------------------------------------------------------
|
|
896
|
-
function handleBusEvents
|
|
901
|
+
function handleBusEvents(_datagram, _echoed) {
|
|
897
902
|
// console.time('handleBusEvents');
|
|
898
903
|
|
|
899
904
|
let _rawValue = null
|
|
@@ -1161,7 +1166,7 @@ return msg;`,
|
|
|
1161
1166
|
node.telegramsQueue.unshift(_clonedMessage) // Add _clonedMessage as first in the queue pile
|
|
1162
1167
|
}
|
|
1163
1168
|
|
|
1164
|
-
function handleTelegramQueue
|
|
1169
|
+
function handleTelegramQueue() {
|
|
1165
1170
|
if (node.knxConnection !== null || node.host.toUpperCase() === 'EMULATE') {
|
|
1166
1171
|
if (node.lockHandleTelegramQueue === true) return // Exits if the funtion is busy
|
|
1167
1172
|
node.lockHandleTelegramQueue = true // Lock the function. It cannot be called again until finished.
|
|
@@ -1310,14 +1315,14 @@ return msg;`,
|
|
|
1310
1315
|
}
|
|
1311
1316
|
|
|
1312
1317
|
// 14/08/2019 If the node has payload same as the received telegram, return false
|
|
1313
|
-
function checkRBEInputFromKNXBusAllowSend
|
|
1318
|
+
function checkRBEInputFromKNXBusAllowSend(_node, _KNXTelegramPayload) {
|
|
1314
1319
|
if (_node.inputRBE !== true) return true
|
|
1315
1320
|
|
|
1316
1321
|
return !_.isEqual(_node.currentPayload, _KNXTelegramPayload)
|
|
1317
1322
|
}
|
|
1318
1323
|
|
|
1319
1324
|
// 26/10/2019 Try to figure out the datapoint type from raw value
|
|
1320
|
-
function tryToFigureOutDataPointFromRawValue
|
|
1325
|
+
function tryToFigureOutDataPointFromRawValue(_rawValue) {
|
|
1321
1326
|
// 25/10/2019 Try some Datapoints
|
|
1322
1327
|
if (_rawValue === null) return '1.001'
|
|
1323
1328
|
if (_rawValue.length === 1) {
|
|
@@ -1363,7 +1368,7 @@ return msg;`,
|
|
|
1363
1368
|
}
|
|
1364
1369
|
}
|
|
1365
1370
|
|
|
1366
|
-
function buildInputMessage
|
|
1371
|
+
function buildInputMessage({ _srcGA, _destGA, _event, _Rawvalue, _inputDpt, _devicename, _outputtopic, _oNode }) {
|
|
1367
1372
|
let sPayloadmeasureunit = 'unknown'
|
|
1368
1373
|
let sDptdesc = 'unknown'
|
|
1369
1374
|
let sPayloadsubtypevalue = 'unknown'
|
|
@@ -1470,7 +1475,7 @@ return msg;`,
|
|
|
1470
1475
|
}
|
|
1471
1476
|
};
|
|
1472
1477
|
|
|
1473
|
-
function readCSV
|
|
1478
|
+
function readCSV(_csvText) {
|
|
1474
1479
|
// 26/05/2023 check if the text is a file path
|
|
1475
1480
|
if (_csvText.toUpperCase().includes('.CSV') || _csvText.toUpperCase().includes('.ESF')) {
|
|
1476
1481
|
// I'ts a file. Read it now and pass to the _csvText
|
|
@@ -1564,7 +1569,7 @@ return msg;`,
|
|
|
1564
1569
|
}
|
|
1565
1570
|
}
|
|
1566
1571
|
|
|
1567
|
-
function readESF
|
|
1572
|
+
function readESF(_esfText) {
|
|
1568
1573
|
// 24/02/2020 must do an EIS to DPT conversion.
|
|
1569
1574
|
// https://www.loxone.com/dede/kb/eibknx-datentypen/
|
|
1570
1575
|
// Format: Attuatori luci.Luci primo piano.0/0/1 Luce camera da letto EIS 1 'Switching' (1 Bit) Low
|
|
@@ -1648,7 +1653,7 @@ return msg;`,
|
|
|
1648
1653
|
}
|
|
1649
1654
|
|
|
1650
1655
|
// 23/08/2019 Delete unwanted CRLF in the GA description
|
|
1651
|
-
function correctCRLFInCSV
|
|
1656
|
+
function correctCRLFInCSV(_csv) {
|
|
1652
1657
|
let sOut = '' // fixed output text to return
|
|
1653
1658
|
let sChar = ''
|
|
1654
1659
|
let bStart = false
|
|
@@ -1681,7 +1686,7 @@ return msg;`,
|
|
|
1681
1686
|
}
|
|
1682
1687
|
|
|
1683
1688
|
// 26/02/2021 Used to send the messages if the node gateway is in EMULATION mode
|
|
1684
|
-
function sendEmulatedTelegram
|
|
1689
|
+
function sendEmulatedTelegram(_msg) {
|
|
1685
1690
|
// INPUT IS
|
|
1686
1691
|
// _msg = {
|
|
1687
1692
|
// grpaddr: '5/0/1',
|
|
@@ -52,6 +52,13 @@
|
|
|
52
52
|
GALightColorCycle: { value: "" },
|
|
53
53
|
dptLightColorCycle: { value: "" },
|
|
54
54
|
|
|
55
|
+
colorAtSwitchOnDayTime: { value: '{"red":255, "green":255, "blue":255}' },
|
|
56
|
+
colorAtSwitchOnNightTime: { value: '{"red":23, "green":4, "blue":0}' },
|
|
57
|
+
|
|
58
|
+
nameDaylightSensor: { value: "" },
|
|
59
|
+
GADaylightSensor: { value: "" },
|
|
60
|
+
dptDaylightSensor: { value: "" },
|
|
61
|
+
|
|
55
62
|
hueDevice: { value: "" }
|
|
56
63
|
},
|
|
57
64
|
inputs: 0,
|
|
@@ -607,6 +614,53 @@
|
|
|
607
614
|
// ########################
|
|
608
615
|
|
|
609
616
|
|
|
617
|
+
// DPT Day/Time sensor
|
|
618
|
+
// ########################
|
|
619
|
+
$.getJSON('knxUltimateDpts', (data) => {
|
|
620
|
+
data.forEach(dpt => {
|
|
621
|
+
if (dpt.value.startsWith("1.")) {
|
|
622
|
+
$("#node-input-dptDaylightSensor").append($("<option></option>")
|
|
623
|
+
.attr("value", dpt.value)
|
|
624
|
+
.text(dpt.text))
|
|
625
|
+
}
|
|
626
|
+
});
|
|
627
|
+
$("#node-input-dptDaylightSensor").val(this.dptDaylightSensor)
|
|
628
|
+
})
|
|
629
|
+
|
|
630
|
+
// Autocomplete suggestion with ETS csv File
|
|
631
|
+
$("#node-input-GADaylightSensor").autocomplete({
|
|
632
|
+
minLength: 1,
|
|
633
|
+
source: function (request, response) {
|
|
634
|
+
//$.getJSON("csv", request, function( data, status, xhr ) {
|
|
635
|
+
$.getJSON("knxUltimatecsv?nodeID=" + oNodeServer.id, (data) => {
|
|
636
|
+
response($.map(data, function (value, key) {
|
|
637
|
+
var sSearch = (value.ga + " (" + value.devicename + ") DPT" + value.dpt);
|
|
638
|
+
if (fullSearch(sSearch, request.term + " 1.")) {
|
|
639
|
+
return {
|
|
640
|
+
label: value.ga + " # " + value.devicename + " # " + value.dpt, // Label for Display
|
|
641
|
+
value: value.ga // Value
|
|
642
|
+
}
|
|
643
|
+
} else {
|
|
644
|
+
return null;
|
|
645
|
+
}
|
|
646
|
+
}));
|
|
647
|
+
});
|
|
648
|
+
}, select: function (event, ui) {
|
|
649
|
+
// Sets Datapoint and device name automatically
|
|
650
|
+
var sDevName = ui.item.label.split("#")[1].trim();
|
|
651
|
+
try {
|
|
652
|
+
sDevName = sDevName.substr(sDevName.indexOf(")") + 1).trim();
|
|
653
|
+
} catch (error) {
|
|
654
|
+
}
|
|
655
|
+
$('#node-input-nameDaylightSensor').val(sDevName);
|
|
656
|
+
var optVal = $("#node-input-dptDaylightSensor option:contains('" + ui.item.label.split("#")[2].trim() + "')").attr('value');
|
|
657
|
+
// Select the option value
|
|
658
|
+
$("#node-input-dptDaylightSensor").val(optVal);
|
|
659
|
+
}
|
|
660
|
+
});
|
|
661
|
+
// ########################
|
|
662
|
+
|
|
663
|
+
|
|
610
664
|
|
|
611
665
|
// Autocomplete suggestion with HUE Lights
|
|
612
666
|
$("#node-input-name").autocomplete({
|
|
@@ -727,6 +781,33 @@
|
|
|
727
781
|
<label for="node-input-nameLightState" style="width:50px; margin-left: 0px; text-align: right;"><span data-i18n="knxUltimateHueLight.node-input-name"></span></label>
|
|
728
782
|
<input type="text" id="node-input-nameLightState" style="width:200px;margin-left: 5px; text-align: left;">
|
|
729
783
|
</div>
|
|
784
|
+
|
|
785
|
+
<div class="form-row">
|
|
786
|
+
<label for="node-input-nameDaylightSensor" style="width:100px;"><i class="fa fa-clock-o"></i> Day/Night</label>
|
|
787
|
+
|
|
788
|
+
<label for="node-input-GADaylightSensor" style="width:20px;">GA</label>
|
|
789
|
+
<input type="text" id="node-input-GADaylightSensor" placeholder="Ex: 1/1/1" style="width:70px;margin-left: 5px; text-align: left;">
|
|
790
|
+
|
|
791
|
+
<label for="node-input-dptDaylightSensor" style="width:40px; margin-left: 0px; text-align: right;">DPT</label>
|
|
792
|
+
<select id="node-input-dptDaylightSensor" style="width:140px;"></select>
|
|
793
|
+
|
|
794
|
+
<label for="node-input-nameDaylightSensor" style="width:50px; margin-left: 0px; text-align: right;"><span data-i18n="knxUltimateHueLight.node-input-name"></span></label>
|
|
795
|
+
<input type="text" id="node-input-nameDaylightSensor" style="width:200px;margin-left: 5px; text-align: left;">
|
|
796
|
+
</div>
|
|
797
|
+
|
|
798
|
+
<div class="form-row">
|
|
799
|
+
<label for="node-input-colorAtSwitchOnDayTime" style="width:200px">
|
|
800
|
+
<i class="fa fa-sun-o"></i> Switch on color at Daytime
|
|
801
|
+
</label>
|
|
802
|
+
<input type="text" id="node-input-colorAtSwitchOnDayTime" placeholder='{"red":255, "green":255, "blue":255}' style="width:250px">
|
|
803
|
+
</div>
|
|
804
|
+
<div class="form-row">
|
|
805
|
+
<label for="node-input-colorAtSwitchOnNightTime" style="width:200px">
|
|
806
|
+
<i class="fa fa-moon-o"></i> Switch on color at Nighttime
|
|
807
|
+
</label>
|
|
808
|
+
<input type="text" id="node-input-colorAtSwitchOnNightTime" placeholder='{"red":100, "green":0, "blue":50}' style="width:250px">
|
|
809
|
+
</div>
|
|
810
|
+
|
|
730
811
|
</p>
|
|
731
812
|
</div>
|
|
732
813
|
<div id="tabs-2">
|
|
@@ -891,7 +972,9 @@ Start typing in the GA field, the name or group address of your KNX device, the
|
|
|
891
972
|
| Brightness Status| Link this to the light's brightness status group address |
|
|
892
973
|
| Blink| *true* Blink the light, *false* Stop blinking. Blinks the light on and off. Useful for signalling. Works with all HUE lights. |
|
|
893
974
|
| Color Cycle| *true* start cycle, *false* Stop cycle. Randomly changes the HUE light's color at regular interval. Works with all HUE lights having color capabilities. |
|
|
894
|
-
|
|
975
|
+
| Day/Night | *true* if daytime, *false* if nighttime. This GA is used to change some behaviours at day or night. |
|
|
976
|
+
| Switch on color at Daytime | You can choose the color/brightness of your light, at switch on, on night time. Set it as JSON object, like { "red": 255, "green": 255, "blue": 255 } |
|
|
977
|
+
| Switch on color at Nighttime | You can choose the color/brightness of your light, at switch on, on night time. Set it as JSON object, like { "red": 100, "green": 0, "blue": 0 } |
|
|
895
978
|
<br/>
|
|
896
979
|
|
|
897
980
|
[Find it useful?](https://www.paypal.me/techtoday)
|
|
@@ -27,6 +27,7 @@ module.exports = function (RED) {
|
|
|
27
27
|
node.formatnegativevalue = 'leave'
|
|
28
28
|
node.formatdecimalsvalue = 2
|
|
29
29
|
node.currentHUEDevice = undefined
|
|
30
|
+
node.DayTime = true
|
|
30
31
|
|
|
31
32
|
// Used to call the status update from the config node.
|
|
32
33
|
node.setNodeStatus = ({ fill, shape, text, payload }) => {
|
|
@@ -45,7 +46,20 @@ module.exports = function (RED) {
|
|
|
45
46
|
switch (msg.knx.destination) {
|
|
46
47
|
case config.GALightSwitch:
|
|
47
48
|
msg.payload = dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptLightSwitch))
|
|
48
|
-
|
|
49
|
+
if (msg.payload) {
|
|
50
|
+
let jColorChoosen = { red: 255, green: 255, blue: 255 }
|
|
51
|
+
if (node.DayTime) {
|
|
52
|
+
jColorChoosen = JSON.parse(config.colorAtSwitchOnDayTime || '{ "red": 255, "green": 255, "blue": 255 }')
|
|
53
|
+
} else {
|
|
54
|
+
jColorChoosen = JSON.parse(config.colorAtSwitchOnNightTime || '{ "red": 255, "green": 255, "blue": 255 }')
|
|
55
|
+
}
|
|
56
|
+
let dgamut = node.currentHUEDevice !== undefined ? node.currentHUEDevice.color.gamut_type : null
|
|
57
|
+
let dretXY = hueColorConverter.ColorConverter.rgbToXy(jColorChoosen.red, jColorChoosen.green, jColorChoosen.blue, dgamut)
|
|
58
|
+
let dbright = hueColorConverter.ColorConverter.getBrightnessFromRGB(jColorChoosen.red, jColorChoosen.green, jColorChoosen.blue)
|
|
59
|
+
state = dbright > 0 ? { on: { on: true }, dimming: { brightness: dbright }, color: { xy: dretXY } } : { on: { on: false } }
|
|
60
|
+
} else {
|
|
61
|
+
state = { on: { on: false } }
|
|
62
|
+
}
|
|
49
63
|
node.serverHue.hueManager.writeHueQueueAdd(config.hueDevice, state, 'setLight')
|
|
50
64
|
break
|
|
51
65
|
case config.GALightDIM:
|
|
@@ -59,6 +73,9 @@ module.exports = function (RED) {
|
|
|
59
73
|
node.startDimStopper('stop')
|
|
60
74
|
}
|
|
61
75
|
break
|
|
76
|
+
case config.GADaylightSensor:
|
|
77
|
+
node.DayTime = Boolean(dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptDaylightSensor)))
|
|
78
|
+
break
|
|
62
79
|
case config.GALightHSV:
|
|
63
80
|
if (config.dptLightHSV === '3.007') {
|
|
64
81
|
// MDT smartbutton will dim the color temperature
|
package/nodes/utils/hueUtils.js
CHANGED
|
@@ -245,20 +245,20 @@ class classHUE extends EventEmitter {
|
|
|
245
245
|
}
|
|
246
246
|
|
|
247
247
|
// Get the light details
|
|
248
|
-
getLightStatus = async (_rid) => {
|
|
248
|
+
getLightStatus = async (_rid) => {
|
|
249
249
|
try {
|
|
250
250
|
const hue = hueApiV2.connect({ host: this.hueBridgeIP, key: this.username })
|
|
251
251
|
const oLight = await hue.getLight(_rid)
|
|
252
252
|
return oLight[0]
|
|
253
|
-
} catch (error) {
|
|
254
|
-
}
|
|
253
|
+
} catch (error) {
|
|
254
|
+
}
|
|
255
255
|
}
|
|
256
256
|
|
|
257
257
|
close = async () => {
|
|
258
258
|
return new Promise((resolve, reject) => {
|
|
259
259
|
try {
|
|
260
260
|
this.closePushEventStream = true
|
|
261
|
-
this.es.close();
|
|
261
|
+
if (this.es !== null) this.es.close();
|
|
262
262
|
this.es = null;
|
|
263
263
|
setTimeout(() => {
|
|
264
264
|
resolve(true)
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"engines": {
|
|
4
4
|
"node": ">=16.0.0"
|
|
5
5
|
},
|
|
6
|
-
"version": "2.1.
|
|
6
|
+
"version": "2.1.15",
|
|
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 handling.",
|
|
8
8
|
"dependencies": {
|
|
9
9
|
"mkdirp": "1.0.4",
|