node-red-contrib-knx-ultimate 2.2.3 → 2.2.5
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 +10 -4
- package/nodes/hue-config.js +36 -17
- package/nodes/knxUltimate-config.js +2 -2
- package/nodes/knxUltimate.html +44 -66
- package/nodes/knxUltimate.js +5 -5
- package/nodes/knxUltimateAlerter.js +190 -190
- package/nodes/knxUltimateHueBattery.js +3 -6
- package/nodes/knxUltimateHueButton.js +2 -1
- package/nodes/knxUltimateHueLight.html +24 -4
- package/nodes/knxUltimateHueLight.js +26 -33
- package/nodes/knxUltimateHueLightSensor.js +3 -6
- package/nodes/knxUltimateHueMotion.js +5 -4
- package/nodes/knxUltimateHueScene.js +2 -1
- package/nodes/knxUltimateHueTapDial.js +2 -1
- package/nodes/knxUltimateHueTemperatureSensor.js +3 -4
- package/nodes/knxUltimateLoadControl.js +1 -1
- package/nodes/locales/en-US/knxUltimate.json +11 -11
- package/nodes/locales/en-US/knxUltimateSceneController.html +3 -3
- package/package.json +1 -1
|
@@ -54,233 +54,233 @@ module.exports = function (RED) {
|
|
|
54
54
|
dpt = (typeof dpt === 'undefined' || dpt == '') ? '' : ' DPT' + dpt
|
|
55
55
|
payload = typeof payload === 'object' ? JSON.stringify(payload) : payload
|
|
56
56
|
node.status({ fill, shape, text: GA + payload + (node.listenallga === true ? ' ' + devicename : '') + ' (' + dDate.getDate() + ', ' + dDate.toLocaleTimeString() + ' ' + text })
|
|
57
|
-
|
|
58
|
-
}
|
|
57
|
+
} catch (error) {
|
|
59
58
|
}
|
|
59
|
+
}
|
|
60
60
|
|
|
61
61
|
// Used to call the status update from the config node.
|
|
62
62
|
node.setLocalStatus = ({ fill, shape, text, payload, GA, dpt, devicename }) => {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
}
|
|
63
|
+
const dDate = new Date()
|
|
64
|
+
// 30/08/2019 Display only the things selected in the config
|
|
65
|
+
GA = (typeof GA === 'undefined' || GA == '') ? '' : '(' + GA + ') '
|
|
66
|
+
devicename = devicename || ''
|
|
67
|
+
dpt = (typeof dpt === 'undefined' || dpt == '') ? '' : ' DPT' + dpt
|
|
68
|
+
try {
|
|
69
|
+
node.status({ fill, shape, text: GA + payload + (node.listenallga === true ? ' ' + devicename : '') + ' (' + dDate.getDate() + ', ' + dDate.toLocaleTimeString() + ' ' + text })
|
|
70
|
+
} catch (error) {
|
|
72
71
|
}
|
|
72
|
+
}
|
|
73
73
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
74
|
+
// This function is called by the knx-ultimate config node, to output a msg.payload.
|
|
75
|
+
node.handleSend = msg => {
|
|
76
|
+
try {
|
|
77
|
+
if (!msg.knx.dpt.startsWith('1.')) return
|
|
78
|
+
} catch (error) {
|
|
79
|
+
return
|
|
80
|
+
}
|
|
81
|
+
let bFound = false // 24/04/2021 true if the cycle below found a match, otherwise false
|
|
82
82
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
}
|
|
96
|
-
node.setLocalStatus({ fill: 'red', shape: 'dot', text: 'Alert', payload: '', GA: msg.topic, dpt: '', devicename: rule.devicename })
|
|
97
|
-
} else {
|
|
98
|
-
// Remove the device from the array
|
|
99
|
-
node.alertedDevices = node.alertedDevices.filter(a => a.topic !== msg.topic)
|
|
100
|
-
node.setLocalStatus({ fill: 'green', shape: 'dot', text: 'Restore', payload: '', GA: msg.topic, dpt: '', devicename: rule.devicename })
|
|
83
|
+
// Update the node.rules with the values taken from the file, if any, otherwise leave the default value
|
|
84
|
+
for (let i = 0; i < node.rules.length; i++) {
|
|
85
|
+
// rule is { topic: rowRuleTopic, devicename: rowRuleDeviceName, longdevicename: rowRuleLongDeviceName}
|
|
86
|
+
var rule = node.rules[i]
|
|
87
|
+
if (msg.topic === rule.topic) {
|
|
88
|
+
if (msg.payload == true) {
|
|
89
|
+
bFound = true
|
|
90
|
+
// Add the device to the array of alertedDevices
|
|
91
|
+
const oTrovato = node.alertedDevices.find(a => a.topic === rule.topic)
|
|
92
|
+
if (oTrovato === undefined) {
|
|
93
|
+
node.alertedDevices.unshift({ topic: rule.topic, devicename: rule.devicename, longdevicename: rule.longdevicename }) // Add to the begin of array
|
|
94
|
+
if (node.whentostart === 'ifnewalert') node.send([null, null, node.getThirdPinMSG()])
|
|
101
95
|
}
|
|
96
|
+
node.setLocalStatus({ fill: 'red', shape: 'dot', text: 'Alert', payload: '', GA: msg.topic, dpt: '', devicename: rule.devicename })
|
|
97
|
+
} else {
|
|
98
|
+
// Remove the device from the array
|
|
99
|
+
node.alertedDevices = node.alertedDevices.filter(a => a.topic !== msg.topic)
|
|
100
|
+
node.setLocalStatus({ fill: 'green', shape: 'dot', text: 'Restore', payload: '', GA: msg.topic, dpt: '', devicename: rule.devicename })
|
|
102
101
|
}
|
|
103
102
|
}
|
|
104
|
-
|
|
105
|
-
// If there's some device to alert, stop current timer and restart
|
|
106
|
-
// This allow the last alerted device to be outputted immediately
|
|
107
|
-
if (bFound && node.whentostart === 'ifnewalert' && node.alertedDevices.length > 0) {
|
|
108
|
-
clearTimeout(node.timerSend)
|
|
109
|
-
// Send directly the second and third message PIN
|
|
110
|
-
node.send([null, node.getSecondPinMSG(), null])
|
|
111
|
-
node.curIndexAlertedDevice = 0 // Restart form the beginning
|
|
112
|
-
node.startTimer()
|
|
113
|
-
}
|
|
114
103
|
}
|
|
115
104
|
|
|
116
|
-
//
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
sTopic += item.topic + ', '
|
|
125
|
-
if (item.devicename !== undefined && item.devicename !== '') sRet += item.devicename + ', '
|
|
126
|
-
if (item.longdevicename !== undefined && item.longdevicename !== '') sRetLong += item.longdevicename + ', '
|
|
127
|
-
})
|
|
128
|
-
sTopic = sTopic.slice(0, -2)
|
|
129
|
-
if (sRet.length > 2) sRet = sRet.slice(0, -2)
|
|
130
|
-
if (sRetLong.length > 2) sRetLong = sRetLong.slice(0, -2)
|
|
131
|
-
msg.topic = sTopic
|
|
132
|
-
msg.devicename = sRet
|
|
133
|
-
msg.longdevicename = sRetLong
|
|
134
|
-
msg.count = node.alertedDevices.length
|
|
135
|
-
msg.payload = true
|
|
136
|
-
return msg
|
|
137
|
-
}
|
|
105
|
+
// If there's some device to alert, stop current timer and restart
|
|
106
|
+
// This allow the last alerted device to be outputted immediately
|
|
107
|
+
if (bFound && node.whentostart === 'ifnewalert' && node.alertedDevices.length > 0) {
|
|
108
|
+
clearTimeout(node.timerSend)
|
|
109
|
+
// Send directly the second and third message PIN
|
|
110
|
+
node.send([null, node.getSecondPinMSG(), null])
|
|
111
|
+
node.curIndexAlertedDevice = 0 // Restart form the beginning
|
|
112
|
+
node.startTimer()
|
|
138
113
|
}
|
|
114
|
+
}
|
|
139
115
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
sTopic
|
|
149
|
-
if (item.devicename !== undefined && item.devicename !== '') sRet
|
|
150
|
-
if (item.longdevicename !== undefined && item.longdevicename !== '') sRetLong
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
116
|
+
// Get the msg to be outputted on second PIN
|
|
117
|
+
node.getSecondPinMSG = () => {
|
|
118
|
+
if (node.alertedDevices.length > 0) {
|
|
119
|
+
const msg = {}
|
|
120
|
+
let sRet = ''
|
|
121
|
+
let sRetLong = ''
|
|
122
|
+
let sTopic = ''
|
|
123
|
+
node.alertedDevices.forEach(function (item) {
|
|
124
|
+
sTopic += item.topic + ', '
|
|
125
|
+
if (item.devicename !== undefined && item.devicename !== '') sRet += item.devicename + ', '
|
|
126
|
+
if (item.longdevicename !== undefined && item.longdevicename !== '') sRetLong += item.longdevicename + ', '
|
|
127
|
+
})
|
|
128
|
+
sTopic = sTopic.slice(0, -2)
|
|
129
|
+
if (sRet.length > 2) sRet = sRet.slice(0, -2)
|
|
130
|
+
if (sRetLong.length > 2) sRetLong = sRetLong.slice(0, -2)
|
|
131
|
+
msg.topic = sTopic
|
|
132
|
+
msg.devicename = sRet
|
|
133
|
+
msg.longdevicename = sRetLong
|
|
134
|
+
msg.count = node.alertedDevices.length
|
|
135
|
+
msg.payload = true
|
|
136
|
+
return msg
|
|
158
137
|
}
|
|
138
|
+
}
|
|
159
139
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
}
|
|
178
|
-
} else {
|
|
179
|
-
node.setLocalStatus({ fill: 'red', shape: 'ring', text: 'No gateway selected. Unable to read from KNX bus', payload: '', GA: '', dpt: '', devicename: '' })
|
|
180
|
-
}
|
|
140
|
+
// Get the msg to be outputted on third PIN
|
|
141
|
+
node.getThirdPinMSG = () => {
|
|
142
|
+
if (node.alertedDevices.length > 0) {
|
|
143
|
+
const msg = {}
|
|
144
|
+
let sRet = ''
|
|
145
|
+
let sRetLong = ''
|
|
146
|
+
let sTopic = ''
|
|
147
|
+
const item = node.alertedDevices[0] // Pick the last alerted device
|
|
148
|
+
sTopic = item.topic
|
|
149
|
+
if (item.devicename !== undefined && item.devicename !== '') sRet = item.devicename
|
|
150
|
+
if (item.longdevicename !== undefined && item.longdevicename !== '') sRetLong = item.longdevicename
|
|
151
|
+
msg.topic = sTopic
|
|
152
|
+
msg.devicename = sRet
|
|
153
|
+
msg.longdevicename = sRetLong
|
|
154
|
+
msg.count = node.alertedDevices.length
|
|
155
|
+
msg.payload = true
|
|
156
|
+
return msg
|
|
181
157
|
}
|
|
158
|
+
}
|
|
182
159
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
160
|
+
// 24/04/2021 perform a read on all GA in the rule list. Called both from node.on("input") and knxUltimate-config
|
|
161
|
+
node.initialReadAllDevicesInRules = () => {
|
|
162
|
+
if (node.server) {
|
|
163
|
+
let grpaddr = ''
|
|
164
|
+
for (let i = 0; i < node.rules.length; i++) {
|
|
165
|
+
// rule is { topic: rowRuleTopic, devicename: rowRuleDeviceName, longdevicename: rowRuleLongDeviceName}
|
|
166
|
+
const rule = node.rules[i]
|
|
167
|
+
// READ: Send a Read request to the bus
|
|
168
|
+
grpaddr = rule.topic
|
|
169
|
+
try {
|
|
170
|
+
// Check if it's a group address
|
|
171
|
+
// const ret = Address.KNXAddress.createFromString(grpaddr, Address.KNXAddress.TYPE_GROUP)
|
|
172
|
+
node.setLocalStatus({ fill: 'grey', shape: 'dot', text: 'Read', payload: '', GA: grpaddr, dpt: '', devicename: rule.devicename })
|
|
173
|
+
node.server.writeQueueAdd({ grpaddr, payload: '', dpt: '', outputtype: 'read', nodecallerid: node.id })
|
|
174
|
+
} catch (error) {
|
|
175
|
+
node.setLocalStatus({ fill: 'grey', shape: 'dot', text: 'Not a KNX GA ' + error.message, payload: '', GA: grpaddr, dpt: '', devicename: rule.devicename })
|
|
194
176
|
}
|
|
195
|
-
return
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
// 24/04/2021 if payload is read or the output type is set to "read", do a read
|
|
199
|
-
if ((msg.hasOwnProperty('readstatus') && msg.readstatus === true)) {
|
|
200
|
-
node.initialReadAllDevicesInRules()
|
|
201
|
-
return
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
if (msg.topic === undefined) {
|
|
205
|
-
node.setLocalStatus({ fill: 'grey', shape: 'dot', text: 'ERROR: You must provide a msg.topic', payload: '', GA: '', dpt: '', devicename: '' })
|
|
206
|
-
return
|
|
207
177
|
}
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
msg.knx = { dpt: '1.001' }
|
|
213
|
-
node.handleSend(msg)
|
|
214
|
-
})
|
|
178
|
+
} else {
|
|
179
|
+
node.setLocalStatus({ fill: 'red', shape: 'ring', text: 'No gateway selected. Unable to read from KNX bus', payload: '', GA: '', dpt: '', devicename: '' })
|
|
180
|
+
}
|
|
181
|
+
}
|
|
215
182
|
|
|
216
|
-
|
|
183
|
+
node.on('input', function (msg) {
|
|
184
|
+
if (typeof msg === 'undefined') return
|
|
185
|
+
if (msg.hasOwnProperty('start')) {
|
|
217
186
|
clearTimeout(node.timerSend)
|
|
218
|
-
|
|
219
|
-
node.server.removeClient(node)
|
|
220
|
-
}
|
|
221
|
-
done()
|
|
222
|
-
})
|
|
223
|
-
|
|
224
|
-
node.handleTimer = () => {
|
|
187
|
+
node.curIndexAlertedDevice = 0 // Restart form the beginning
|
|
225
188
|
if (node.alertedDevices.length > 0) {
|
|
226
|
-
|
|
227
|
-
if (node.curIndexAlertedDevice > count - 1) {
|
|
228
|
-
node.curIndexAlertedDevice = 0
|
|
229
|
-
if (node.whentostart === 'manualstart') {
|
|
230
|
-
node.curIndexAlertedDevice = 0 // Restart form the beginning
|
|
231
|
-
return
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
// Create output message
|
|
235
|
-
try {
|
|
236
|
-
const curDev = node.alertedDevices[node.curIndexAlertedDevice] // is { topic: rule.topic, devicename: rule.devicename }
|
|
237
|
-
const msg = {}
|
|
238
|
-
msg.topic = curDev.topic
|
|
239
|
-
msg.count = count
|
|
240
|
-
msg.devicename = curDev.devicename
|
|
241
|
-
msg.longdevicename = curDev.longdevicename
|
|
242
|
-
msg.payload = true
|
|
243
|
-
node.send([msg, null, null])
|
|
244
|
-
} catch (error) {
|
|
245
|
-
}
|
|
246
|
-
node.curIndexAlertedDevice += 1
|
|
247
|
-
// Restart timer
|
|
189
|
+
node.send([null, node.getSecondPinMSG(), node.getThirdPinMSG()])
|
|
248
190
|
node.startTimer()
|
|
249
191
|
} else {
|
|
250
192
|
// Nothing more to output
|
|
251
193
|
node.sendNoMoreDevices()
|
|
252
194
|
}
|
|
195
|
+
return
|
|
253
196
|
}
|
|
254
197
|
|
|
255
|
-
//
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
node.handleTimer()
|
|
260
|
-
}, node.timerinterval * 1000)
|
|
198
|
+
// 24/04/2021 if payload is read or the Telegram type is set to "read", do a read
|
|
199
|
+
if ((msg.hasOwnProperty('readstatus') && msg.readstatus === true)) {
|
|
200
|
+
node.initialReadAllDevicesInRules()
|
|
201
|
+
return
|
|
261
202
|
}
|
|
262
203
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
msg.topic = ''
|
|
267
|
-
msg.count = 0
|
|
268
|
-
msg.devicename = ''
|
|
269
|
-
msg.longdevicename = ''
|
|
270
|
-
msg.payload = false
|
|
271
|
-
node.send([msg, msg, msg])
|
|
204
|
+
if (msg.topic === undefined) {
|
|
205
|
+
node.setLocalStatus({ fill: 'grey', shape: 'dot', text: 'ERROR: You must provide a msg.topic', payload: '', GA: '', dpt: '', devicename: '' })
|
|
206
|
+
return
|
|
272
207
|
}
|
|
208
|
+
if (msg.payload === undefined) {
|
|
209
|
+
node.setLocalStatus({ fill: 'grey', shape: 'dot', text: 'ERROR: You must provide payload (true/false)', payload: '', GA: '', dpt: '', devicename: '' })
|
|
210
|
+
return
|
|
211
|
+
}
|
|
212
|
+
msg.knx = { dpt: '1.001' }
|
|
213
|
+
node.handleSend(msg)
|
|
214
|
+
})
|
|
273
215
|
|
|
274
|
-
|
|
275
|
-
node.
|
|
276
|
-
|
|
277
|
-
// On each deploy, unsubscribe+resubscribe
|
|
216
|
+
node.on('close', function (done) {
|
|
217
|
+
clearTimeout(node.timerSend)
|
|
278
218
|
if (node.server) {
|
|
279
219
|
node.server.removeClient(node)
|
|
280
|
-
|
|
281
|
-
|
|
220
|
+
}
|
|
221
|
+
done()
|
|
222
|
+
})
|
|
223
|
+
|
|
224
|
+
node.handleTimer = () => {
|
|
225
|
+
if (node.alertedDevices.length > 0) {
|
|
226
|
+
const count = node.alertedDevices.length
|
|
227
|
+
if (node.curIndexAlertedDevice > count - 1) {
|
|
228
|
+
node.curIndexAlertedDevice = 0
|
|
229
|
+
if (node.whentostart === 'manualstart') {
|
|
230
|
+
node.curIndexAlertedDevice = 0 // Restart form the beginning
|
|
231
|
+
return
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
// Create output message
|
|
235
|
+
try {
|
|
236
|
+
const curDev = node.alertedDevices[node.curIndexAlertedDevice] // is { topic: rule.topic, devicename: rule.devicename }
|
|
237
|
+
const msg = {}
|
|
238
|
+
msg.topic = curDev.topic
|
|
239
|
+
msg.count = count
|
|
240
|
+
msg.devicename = curDev.devicename
|
|
241
|
+
msg.longdevicename = curDev.longdevicename
|
|
242
|
+
msg.payload = true
|
|
243
|
+
node.send([msg, null, null])
|
|
244
|
+
} catch (error) {
|
|
282
245
|
}
|
|
246
|
+
node.curIndexAlertedDevice += 1
|
|
247
|
+
// Restart timer
|
|
248
|
+
node.startTimer()
|
|
249
|
+
} else {
|
|
250
|
+
// Nothing more to output
|
|
251
|
+
node.sendNoMoreDevices()
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Start timer
|
|
256
|
+
node.startTimer = () => {
|
|
257
|
+
clearTimeout(node.timerSend)
|
|
258
|
+
node.timerSend = setTimeout(() => {
|
|
259
|
+
node.handleTimer()
|
|
260
|
+
}, node.timerinterval * 1000)
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// As soon as there no more devices..
|
|
264
|
+
node.sendNoMoreDevices = () => {
|
|
265
|
+
const msg = {}
|
|
266
|
+
msg.topic = ''
|
|
267
|
+
msg.count = 0
|
|
268
|
+
msg.devicename = ''
|
|
269
|
+
msg.longdevicename = ''
|
|
270
|
+
msg.payload = false
|
|
271
|
+
node.send([msg, msg, msg])
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// Init
|
|
275
|
+
node.sendNoMoreDevices()
|
|
276
|
+
|
|
277
|
+
// On each deploy, unsubscribe+resubscribe
|
|
278
|
+
if (node.server) {
|
|
279
|
+
node.server.removeClient(node)
|
|
280
|
+
if (node.topic !== '' || node.topicSave !== '') {
|
|
281
|
+
node.server.addClient(node)
|
|
283
282
|
}
|
|
284
283
|
}
|
|
285
|
-
RED.nodes.registerType('knxUltimateAlerter', knxUltimateAlerter)
|
|
286
284
|
}
|
|
285
|
+
RED.nodes.registerType('knxUltimateAlerter', knxUltimateAlerter)
|
|
286
|
+
}
|
|
@@ -22,6 +22,7 @@ module.exports = function (RED) {
|
|
|
22
22
|
node.formatmultiplyvalue = 1;
|
|
23
23
|
node.formatnegativevalue = 'leave';
|
|
24
24
|
node.formatdecimalsvalue = 2;
|
|
25
|
+
node.hueDevice = config.hueDevice;
|
|
25
26
|
|
|
26
27
|
// Used to call the status update from the config node.
|
|
27
28
|
node.setNodeStatus = ({
|
|
@@ -33,7 +34,7 @@ module.exports = function (RED) {
|
|
|
33
34
|
node.setNodeStatusHue = ({
|
|
34
35
|
fill, shape, text, payload,
|
|
35
36
|
}) => {
|
|
36
|
-
if (payload === undefined)
|
|
37
|
+
if (payload === undefined) payload = '';
|
|
37
38
|
const dDate = new Date();
|
|
38
39
|
payload = typeof payload === 'object' ? JSON.stringify(payload) : payload.toString();
|
|
39
40
|
node.status({ fill, shape, text: `${text} ${payload} (${dDate.getDate()}, ${dDate.toLocaleTimeString()})` });
|
|
@@ -83,11 +84,7 @@ module.exports = function (RED) {
|
|
|
83
84
|
}
|
|
84
85
|
if (node.serverHue) {
|
|
85
86
|
node.serverHue.removeClient(node);
|
|
86
|
-
|
|
87
|
-
// I queue the state request, by passing the callback to call whenever the HUE bridge send me the light status async
|
|
88
|
-
if (node.serverHue !== null && node.serverHue.hueManager !== null) {
|
|
89
|
-
node.serverHue.addClient(node);
|
|
90
|
-
}
|
|
87
|
+
node.serverHue.addClient(node);
|
|
91
88
|
}
|
|
92
89
|
|
|
93
90
|
node.on('input', (msg) => {
|
|
@@ -26,6 +26,7 @@ module.exports = function (RED) {
|
|
|
26
26
|
node.formatdecimalsvalue = 2;
|
|
27
27
|
node.short_releaseValue = false;
|
|
28
28
|
node.isTimerDimStopRunning = false;
|
|
29
|
+
node.hueDevice = config.hueDevice;
|
|
29
30
|
|
|
30
31
|
// Used to call the status update from the config node.
|
|
31
32
|
node.setNodeStatus = ({
|
|
@@ -37,7 +38,7 @@ module.exports = function (RED) {
|
|
|
37
38
|
node.setNodeStatusHue = ({
|
|
38
39
|
fill, shape, text, payload,
|
|
39
40
|
}) => {
|
|
40
|
-
if (payload === undefined)
|
|
41
|
+
if (payload === undefined) payload = '';
|
|
41
42
|
const dDate = new Date();
|
|
42
43
|
payload = typeof payload === 'object' ? JSON.stringify(payload) : payload.toString();
|
|
43
44
|
node.status({ fill, shape, text: `${text} ${payload} (${dDate.getDate()}, ${dDate.toLocaleTimeString()})` });
|
|
@@ -1,4 +1,24 @@
|
|
|
1
1
|
<script type="text/javascript">
|
|
2
|
+
RED.events.on('nodes:add', function (node) {
|
|
3
|
+
if (node.type === 'uibuilder') {
|
|
4
|
+
// Keep a list of uib nodes in the editor
|
|
5
|
+
// may be different to the deployed list
|
|
6
|
+
editorInstances[node.id] = node.url
|
|
7
|
+
// -- IF uibuilderInstances <> editorInstances THEN there are undeployed instances. --
|
|
8
|
+
}
|
|
9
|
+
})
|
|
10
|
+
RED.events.on('nodes:change', function (node) {
|
|
11
|
+
if (node.type === 'uibuilder') {
|
|
12
|
+
mylog('nodes:change:', node)
|
|
13
|
+
editorInstances[node.id] = node.url
|
|
14
|
+
}
|
|
15
|
+
})
|
|
16
|
+
RED.events.on('nodes:remove', function (node) {
|
|
17
|
+
if (node.type === 'uibuilder') {
|
|
18
|
+
mylog('>> nodes:remove >>', node)
|
|
19
|
+
delete editorInstances[node.id]
|
|
20
|
+
}
|
|
21
|
+
})
|
|
2
22
|
RED.nodes.registerType("knxUltimateHueLight", {
|
|
3
23
|
category: "KNX Ultimate",
|
|
4
24
|
color: "#C0C7E9",
|
|
@@ -486,15 +506,15 @@
|
|
|
486
506
|
$("#getColorAtSwitchOnNightTimeButton").text("Get current");
|
|
487
507
|
});
|
|
488
508
|
});
|
|
489
|
-
|
|
509
|
+
|
|
490
510
|
// Fill options for minDimLevel and maxDimLevel
|
|
491
511
|
for (let index = 0; index <= 90; index++) {
|
|
492
|
-
if (index === 0){
|
|
512
|
+
if (index === 0) {
|
|
493
513
|
$("#node-input-minDimLevelLight").append($("<option>").val(index).text(index.toString() + "% (Switch Off)"));
|
|
494
|
-
}else{
|
|
514
|
+
} else {
|
|
495
515
|
$("#node-input-minDimLevelLight").append($("<option>").val(index).text(index.toString() + "%"));
|
|
496
516
|
}
|
|
497
|
-
|
|
517
|
+
|
|
498
518
|
}
|
|
499
519
|
$("#node-input-minDimLevelLight").val(node.minDimLevelLight);
|
|
500
520
|
for (let index = 100; index >= 10; index--) {
|
|
@@ -41,22 +41,13 @@ module.exports = function (RED) {
|
|
|
41
41
|
fill, shape, text, payload,
|
|
42
42
|
}) => { };
|
|
43
43
|
// Used to call the status update from the HUE config node.
|
|
44
|
-
node.setNodeStatusHue = ({
|
|
45
|
-
|
|
46
|
-
}) => {
|
|
47
|
-
if (payload === undefined) return;
|
|
44
|
+
node.setNodeStatusHue = ({ fill, shape, text, payload }) => {
|
|
45
|
+
if (payload === undefined) payload = '';
|
|
48
46
|
const dDate = new Date();
|
|
49
47
|
payload = typeof payload === "object" ? JSON.stringify(payload) : payload.toString();
|
|
50
48
|
node.status({ fill, shape, text: `${text} ${payload} (${dDate.getDate()}, ${dDate.toLocaleTimeString()})` });
|
|
51
49
|
};
|
|
52
50
|
|
|
53
|
-
node.setNodeStatusHue({
|
|
54
|
-
fill: "grey",
|
|
55
|
-
shape: "ring",
|
|
56
|
-
text: "Connecting to the Bridge...",
|
|
57
|
-
payload: "",
|
|
58
|
-
});
|
|
59
|
-
|
|
60
51
|
function getRandomIntInclusive(min, max) {
|
|
61
52
|
min = Math.ceil(min);
|
|
62
53
|
max = Math.floor(max);
|
|
@@ -69,7 +60,7 @@ module.exports = function (RED) {
|
|
|
69
60
|
node.setNodeStatusHue({
|
|
70
61
|
fill: "red",
|
|
71
62
|
shape: "ring",
|
|
72
|
-
text: "
|
|
63
|
+
text: "Currently not ready.",
|
|
73
64
|
payload: "",
|
|
74
65
|
});
|
|
75
66
|
return;
|
|
@@ -448,26 +439,32 @@ module.exports = function (RED) {
|
|
|
448
439
|
node.currentHUEDevice.on.on = _event.on.on;
|
|
449
440
|
}
|
|
450
441
|
if (_event.hasOwnProperty("color")) {
|
|
451
|
-
|
|
452
|
-
|
|
442
|
+
if (_event.type !== 'grouped_light') {
|
|
443
|
+
// In grouped lights, there is group color, but each light has it's own color.
|
|
444
|
+
node.updateKNXLightColorState(_event.color);
|
|
445
|
+
node.currentHUEDevice.color = _event.color;
|
|
446
|
+
}
|
|
453
447
|
}
|
|
454
448
|
if (_event.hasOwnProperty("dimming") && _event.dimming.brightness !== undefined) {
|
|
455
449
|
// Every once on a time, the light transmit the brightness value of 0.39.
|
|
456
450
|
// To avoid wrongly turn light state on, exit
|
|
457
451
|
if (_event.dimming.brightness < 1) _event.dimming.brightness = 0;
|
|
458
|
-
if (node.currentHUEDevice.hasOwnProperty("on") && node.currentHUEDevice.on.on === false && _event.dimming.brightness === 0)
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
452
|
+
if (node.currentHUEDevice.hasOwnProperty("on") && node.currentHUEDevice.on.on === false && _event.dimming.brightness === 0) {
|
|
453
|
+
// Do nothing, because the light is off and the dimming also is 0
|
|
454
|
+
} else {
|
|
455
|
+
if (node.currentHUEDevice.on.on === false) node.updateKNXLightState(_event.dimming.brightness > 0);
|
|
456
|
+
node.updateKNXBrightnessState(_event.dimming.brightness);
|
|
457
|
+
// If the brightness reaches zero, the hue lamp "on" property must be set to zero as well
|
|
458
|
+
if (_event.dimming.brightness === 0) {
|
|
459
|
+
node.serverHue.hueManager.writeHueQueueAdd(
|
|
460
|
+
node.hueDevice,
|
|
461
|
+
{ on: { on: false } },
|
|
462
|
+
node.isGrouped_light === false ? "setLight" : "setGroupedLight",
|
|
463
|
+
);
|
|
464
|
+
node.currentHUEDevice.on.on = false;
|
|
465
|
+
}
|
|
466
|
+
node.currentHUEDevice.dimming.brightness = _event.dimming.brightness;
|
|
469
467
|
}
|
|
470
|
-
node.currentHUEDevice.dimming.brightness = _event.dimming.brightness;
|
|
471
468
|
}
|
|
472
469
|
if (_event.hasOwnProperty("color_temperature") && _event.color_temperature.mirek !== undefined) {
|
|
473
470
|
node.updateKNXLightHSVState(_event.color_temperature.mirek);
|
|
@@ -615,6 +612,8 @@ module.exports = function (RED) {
|
|
|
615
612
|
}
|
|
616
613
|
};
|
|
617
614
|
|
|
615
|
+
|
|
616
|
+
|
|
618
617
|
// On each deploy, unsubscribe+resubscribe
|
|
619
618
|
if (node.server) {
|
|
620
619
|
node.server.removeClient(node);
|
|
@@ -622,13 +621,7 @@ module.exports = function (RED) {
|
|
|
622
621
|
}
|
|
623
622
|
if (node.serverHue) {
|
|
624
623
|
node.serverHue.removeClient(node);
|
|
625
|
-
|
|
626
|
-
try {
|
|
627
|
-
node.serverHue.addClient(node);
|
|
628
|
-
} catch (err) {
|
|
629
|
-
RED.log.error(`Errore knxUltimateHueLight node.currentHUEDevice ${err.message}`);
|
|
630
|
-
}
|
|
631
|
-
}
|
|
624
|
+
node.serverHue.addClient(node);
|
|
632
625
|
}
|
|
633
626
|
|
|
634
627
|
node.on("input", (msg) => { });
|
|
@@ -22,6 +22,7 @@ module.exports = function (RED) {
|
|
|
22
22
|
node.formatmultiplyvalue = 1;
|
|
23
23
|
node.formatnegativevalue = 'leave';
|
|
24
24
|
node.formatdecimalsvalue = 2;
|
|
25
|
+
node.hueDevice = config.hueDevice;
|
|
25
26
|
|
|
26
27
|
// Used to call the status update from the config node.
|
|
27
28
|
node.setNodeStatus = ({ fill, shape, text, payload }) => {
|
|
@@ -29,7 +30,7 @@ module.exports = function (RED) {
|
|
|
29
30
|
};
|
|
30
31
|
// Used to call the status update from the HUE config node.
|
|
31
32
|
node.setNodeStatusHue = ({ fill, shape, text, payload }) => {
|
|
32
|
-
if (payload === undefined)
|
|
33
|
+
if (payload === undefined) payload = '';
|
|
33
34
|
const dDate = new Date();
|
|
34
35
|
payload = typeof payload === 'object' ? JSON.stringify(payload) : payload.toString();
|
|
35
36
|
node.status({ fill, shape, text: text + ' ' + payload + ' (' + dDate.getDate() + ', ' + dDate.toLocaleTimeString() + ')' });
|
|
@@ -76,11 +77,7 @@ module.exports = function (RED) {
|
|
|
76
77
|
}
|
|
77
78
|
if (node.serverHue) {
|
|
78
79
|
node.serverHue.removeClient(node);
|
|
79
|
-
|
|
80
|
-
// I queue the state request, by passing the callback to call whenever the HUE bridge send me the light status async
|
|
81
|
-
if (node.serverHue !== null && node.serverHue.hueManager !== null) {
|
|
82
|
-
node.serverHue.addClient(node);
|
|
83
|
-
}
|
|
80
|
+
node.serverHue.addClient(node);
|
|
84
81
|
}
|
|
85
82
|
|
|
86
83
|
node.on('input', function (msg) {
|