node-red-contrib-ccu 3.4.2 → 4.0.0
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/.prettierignore +10 -0
- package/.prettierrc +14 -0
- package/AGENTS.md +96 -0
- package/CHANGELOG.md +66 -0
- package/README.md +17 -21
- package/ROADMAP.md +402 -0
- package/eslint.config.js +45 -0
- package/examples/rpc-events.json +65 -0
- package/examples/switch-datapoint.json +86 -0
- package/examples/system-variable.json +60 -0
- package/nodes/ccu-alexa.html +12 -7
- package/nodes/ccu-alexa.js +33 -14
- package/nodes/ccu-connection.html +9 -1
- package/nodes/ccu-connection.js +588 -335
- package/nodes/ccu-display.html +11 -4
- package/nodes/ccu-display.js +26 -9
- package/nodes/ccu-get-value.html +13 -4
- package/nodes/ccu-get-value.js +2 -2
- package/nodes/ccu-mqtt.html +9 -10
- package/nodes/ccu-mqtt.js +55 -29
- package/nodes/ccu-program.html +1 -1
- package/nodes/ccu-program.js +9 -7
- package/nodes/ccu-rpc-event.html +12 -7
- package/nodes/ccu-rpc-event.js +4 -5
- package/nodes/ccu-rpc.html +12 -5
- package/nodes/ccu-rpc.js +8 -6
- package/nodes/ccu-script.html +1 -1
- package/nodes/ccu-script.js +4 -3
- package/nodes/ccu-set-value.html +11 -7
- package/nodes/ccu-set-value.js +40 -16
- package/nodes/ccu-signal.html +11 -5
- package/nodes/ccu-signal.js +34 -23
- package/nodes/ccu-switch.html +13 -5
- package/nodes/ccu-sysvar.html +1 -1
- package/nodes/ccu-sysvar.js +11 -7
- package/nodes/ccu-value.html +12 -7
- package/nodes/ccu-value.js +36 -13
- package/nodes/lib/base62.js +22 -0
- package/nodes/lib/discover.js +127 -0
- package/nodes/lib/nextport.js +30 -0
- package/nodes/lib/similarity.js +51 -0
- package/nodes/lib/status.js +1 -1
- package/package.json +105 -155
- package/roadmap-archive/README.md +20 -0
- package/roadmap-archive/phase-1.md +48 -0
- package/roadmap-archive/todo-history.md +39 -0
- package/TODO.md +0 -41
- package/ccu_rega_localhost.json +0 -1
- package/ccu_values_localhost.json +0 -1
package/nodes/ccu-rpc.html
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
return false;
|
|
15
15
|
}
|
|
16
16
|
}},
|
|
17
|
-
topic: {value: '${CCU}/${Interface}/${Method}'}
|
|
17
|
+
topic: {value: '${CCU}/${Interface}/${Method}'}
|
|
18
18
|
},
|
|
19
19
|
inputs: 1,
|
|
20
20
|
outputs: 1,
|
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
|
|
35
35
|
let ifacesLoaded = false;
|
|
36
36
|
let ifacesPending = false;
|
|
37
|
+
let ifaceLoadRetries = 5;
|
|
37
38
|
|
|
38
39
|
function loadIfaces(iface, cb) {
|
|
39
40
|
if (ifacesPending) {
|
|
@@ -41,7 +42,6 @@
|
|
|
41
42
|
}
|
|
42
43
|
|
|
43
44
|
ifacesPending = true;
|
|
44
|
-
console.log('loadIfaces()');
|
|
45
45
|
$nodeInputIface.html('<option></option>');
|
|
46
46
|
const nodeId = $nodeInputCcuConfig.val();
|
|
47
47
|
if (nodeId === '_ADD_') {
|
|
@@ -59,12 +59,17 @@
|
|
|
59
59
|
cb();
|
|
60
60
|
ifacesPending = false;
|
|
61
61
|
}
|
|
62
|
+
}).fail(() => {
|
|
63
|
+
// config node not (yet) available in the runtime - allow retrying
|
|
64
|
+
ifacesPending = false;
|
|
65
|
+
if (ifaceLoadRetries-- > 0) {
|
|
66
|
+
setTimeout(() => loadIfaces(iface, cb), 1000);
|
|
67
|
+
}
|
|
62
68
|
});
|
|
63
69
|
}
|
|
64
70
|
}
|
|
65
71
|
|
|
66
72
|
$nodeInputCcuConfig.change(() => {
|
|
67
|
-
console.log('$nodeInputCcuConfig change');
|
|
68
73
|
loadIfaces(this.iface, () => {
|
|
69
74
|
ifacesLoaded = true;
|
|
70
75
|
$nodeInputIface.removeAttr('disabled');
|
|
@@ -72,6 +77,10 @@
|
|
|
72
77
|
});
|
|
73
78
|
});
|
|
74
79
|
|
|
80
|
+
// Node-RED 4.x does not reliably fire the change event on dialog
|
|
81
|
+
// open - trigger the initial load explicitly (see ROADMAP.md 8.1)
|
|
82
|
+
$nodeInputCcuConfig.trigger('change');
|
|
83
|
+
|
|
75
84
|
$('#node-input-method').autocomplete({
|
|
76
85
|
source: [],
|
|
77
86
|
close: () => {
|
|
@@ -83,7 +92,6 @@
|
|
|
83
92
|
|
|
84
93
|
$('#node-input-iface').change(() => {
|
|
85
94
|
if (ifacesLoaded) {
|
|
86
|
-
console.log('#node-input-iface change');
|
|
87
95
|
autocompleteMethods();
|
|
88
96
|
}
|
|
89
97
|
});
|
|
@@ -116,7 +124,6 @@
|
|
|
116
124
|
methods = [];
|
|
117
125
|
}
|
|
118
126
|
|
|
119
|
-
console.log('autocompleteMethods', iface, methods.length);
|
|
120
127
|
$('#node-input-method').autocomplete('option', 'source', methods);
|
|
121
128
|
}
|
|
122
129
|
}
|
package/nodes/ccu-rpc.js
CHANGED
|
@@ -37,27 +37,29 @@ module.exports = function (RED) {
|
|
|
37
37
|
} else if (method === 'putParamset') {
|
|
38
38
|
let [address, paramset, values] = parameters;
|
|
39
39
|
values = values || {};
|
|
40
|
-
Object.keys(values).forEach(parameter => {
|
|
40
|
+
Object.keys(values).forEach((parameter) => {
|
|
41
41
|
values[parameter] = this.ccu.paramCast(iface, address, paramset, parameter, values[parameter]);
|
|
42
42
|
});
|
|
43
43
|
parameters[2] = values;
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
this.ccu
|
|
47
|
-
.
|
|
46
|
+
this.ccu
|
|
47
|
+
.methodCall(iface, method, parameters)
|
|
48
|
+
.then((res) => {
|
|
48
49
|
const message = {
|
|
49
50
|
ccu: this.ccu.host,
|
|
50
51
|
iface,
|
|
51
52
|
topic: config.topic,
|
|
52
53
|
payload: res,
|
|
53
|
-
ts:
|
|
54
|
-
method
|
|
54
|
+
ts: new Date().getTime(),
|
|
55
|
+
method,
|
|
55
56
|
};
|
|
56
57
|
message.topic = this.ccu.topicReplace(config.topic, message);
|
|
57
58
|
send(message);
|
|
58
59
|
|
|
59
60
|
done();
|
|
60
|
-
})
|
|
61
|
+
})
|
|
62
|
+
.catch((error) => {
|
|
61
63
|
done(error);
|
|
62
64
|
});
|
|
63
65
|
});
|
package/nodes/ccu-script.html
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
name: {value: ''},
|
|
7
7
|
script: {value: ''},
|
|
8
8
|
ccuConfig: {value: 'localhost', type: 'ccu-connection', required: true},
|
|
9
|
-
topic: {value: '${CCU}/${Interface}'}
|
|
9
|
+
topic: {value: '${CCU}/${Interface}'}
|
|
10
10
|
},
|
|
11
11
|
inputs: 1,
|
|
12
12
|
outputs: 1,
|
package/nodes/ccu-script.js
CHANGED
|
@@ -21,8 +21,9 @@ module.exports = function (RED) {
|
|
|
21
21
|
_input(message, send, done) {
|
|
22
22
|
let script = this.script || message.payload;
|
|
23
23
|
script += '\n\nvar nr_script_call_success = true;\n';
|
|
24
|
-
this.ccu
|
|
25
|
-
.
|
|
24
|
+
this.ccu
|
|
25
|
+
.script(script)
|
|
26
|
+
.then((message) => {
|
|
26
27
|
message.iface = this.iface;
|
|
27
28
|
message.ccu = this.ccu.host;
|
|
28
29
|
message.topic = this.ccu.topicReplace(this.topic, message);
|
|
@@ -36,7 +37,7 @@ module.exports = function (RED) {
|
|
|
36
37
|
done(new Error('Script call failed'));
|
|
37
38
|
}
|
|
38
39
|
})
|
|
39
|
-
.catch(error => {
|
|
40
|
+
.catch((error) => {
|
|
40
41
|
this.status({fill: 'red', shape: 'dot', text: 'error'});
|
|
41
42
|
done(error);
|
|
42
43
|
});
|
package/nodes/ccu-set-value.html
CHANGED
|
@@ -49,6 +49,7 @@
|
|
|
49
49
|
|
|
50
50
|
let ifacesLoaded = false;
|
|
51
51
|
let ifacesPending = false;
|
|
52
|
+
let ifaceLoadRetries = 5;
|
|
52
53
|
|
|
53
54
|
$('#node-input-force-dropdown').val(String(Boolean(this.force)));
|
|
54
55
|
|
|
@@ -96,7 +97,6 @@
|
|
|
96
97
|
}
|
|
97
98
|
|
|
98
99
|
ifacesPending = true;
|
|
99
|
-
console.log('loadIfaces()');
|
|
100
100
|
$nodeInputIface.html('<option value="">*</option>');
|
|
101
101
|
const nodeId = $nodeInputCcuConfig.val();
|
|
102
102
|
if (nodeId === '_ADD_') {
|
|
@@ -116,6 +116,12 @@
|
|
|
116
116
|
cb();
|
|
117
117
|
ifacesPending = false;
|
|
118
118
|
}
|
|
119
|
+
}).fail(() => {
|
|
120
|
+
// config node not (yet) available in the runtime - allow retrying
|
|
121
|
+
ifacesPending = false;
|
|
122
|
+
if (ifaceLoadRetries-- > 0) {
|
|
123
|
+
setTimeout(() => loadIfaces(iface, cb), 1000);
|
|
124
|
+
}
|
|
119
125
|
});
|
|
120
126
|
}
|
|
121
127
|
}
|
|
@@ -128,15 +134,17 @@
|
|
|
128
134
|
});
|
|
129
135
|
});
|
|
130
136
|
|
|
137
|
+
// Node-RED 4.x does not reliably fire the change event on dialog
|
|
138
|
+
// open - trigger the initial load explicitly (see ROADMAP.md 8.1)
|
|
139
|
+
$nodeInputCcuConfig.trigger('change');
|
|
140
|
+
|
|
131
141
|
function loadConfig() {
|
|
132
142
|
if (ifacesLoaded) {
|
|
133
|
-
console.log('loadConfig');
|
|
134
143
|
const nodeId = $nodeInputCcuConfig.val();
|
|
135
144
|
const url = 'ccu?config=' + nodeId;
|
|
136
145
|
$.getJSON(url, d => {
|
|
137
146
|
data = d;
|
|
138
147
|
processChannelAssignments();
|
|
139
|
-
console.log('data', data);
|
|
140
148
|
autocomplete();
|
|
141
149
|
});
|
|
142
150
|
}
|
|
@@ -150,7 +158,6 @@
|
|
|
150
158
|
data.nameChannels = {};
|
|
151
159
|
data.nameDevices = {};
|
|
152
160
|
|
|
153
|
-
console.log(data);
|
|
154
161
|
|
|
155
162
|
Object.keys(data.channelRooms).forEach(channel => {
|
|
156
163
|
const room = data.channelRooms[channel];
|
|
@@ -236,7 +243,6 @@
|
|
|
236
243
|
const channelNames = $('#node-input-channelName').val() ? [$('#node-input-channelName').val()] : [];
|
|
237
244
|
const channelTypes = $('#node-input-channelType').val() ? [$('#node-input-channelType').val()] : [];
|
|
238
245
|
//const channelIndexes = $('#node-input-channelIndex').val() ? [$('#node-input-channelIndex').val()] : [];
|
|
239
|
-
const datapoints = $('#node-input-datapoint').val() ? [$('#node-input-datapoint').val()] : [];
|
|
240
246
|
|
|
241
247
|
const lists = {
|
|
242
248
|
device: [],
|
|
@@ -292,7 +298,6 @@
|
|
|
292
298
|
}
|
|
293
299
|
}
|
|
294
300
|
|
|
295
|
-
console.log('autocomplete', {iface, rooms, funcs, devices, deviceNames, deviceTypes, channels, channelNames, channelTypes, datapoints});
|
|
296
301
|
|
|
297
302
|
function checkDatapoint(datapoint) {
|
|
298
303
|
let deviceCheck = false;
|
|
@@ -476,7 +481,6 @@
|
|
|
476
481
|
});
|
|
477
482
|
}
|
|
478
483
|
|
|
479
|
-
console.log('lists', lists);
|
|
480
484
|
|
|
481
485
|
Object.keys(lists).forEach(key => {
|
|
482
486
|
if (key === 'channelIndex') {
|
package/nodes/ccu-set-value.js
CHANGED
|
@@ -37,13 +37,13 @@ module.exports = function (RED) {
|
|
|
37
37
|
channelIndexRx: config.channelIndexRx,
|
|
38
38
|
channelNameRx: config.channelNameRx,
|
|
39
39
|
datapointRx: config.datapointRx,
|
|
40
|
-
force: config.force
|
|
40
|
+
force: config.force,
|
|
41
41
|
};
|
|
42
42
|
|
|
43
43
|
this.blacklist = new Set();
|
|
44
44
|
this.whitelist = new Set();
|
|
45
45
|
|
|
46
|
-
this.on('input', message => {
|
|
46
|
+
this.on('input', (message) => {
|
|
47
47
|
this.setValues(message);
|
|
48
48
|
});
|
|
49
49
|
|
|
@@ -66,7 +66,7 @@ module.exports = function (RED) {
|
|
|
66
66
|
setValues(message) {
|
|
67
67
|
const {config} = this;
|
|
68
68
|
let dynamicConfig = false;
|
|
69
|
-
Object.keys(config).forEach(key => {
|
|
69
|
+
Object.keys(config).forEach((key) => {
|
|
70
70
|
if (!config[key]) {
|
|
71
71
|
if (key in message) {
|
|
72
72
|
dynamicConfig = true;
|
|
@@ -81,12 +81,12 @@ module.exports = function (RED) {
|
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
let count = 0;
|
|
84
|
-
Object.keys(this.ccu.metadata.devices).forEach(iface => {
|
|
84
|
+
Object.keys(this.ccu.metadata.devices).forEach((iface) => {
|
|
85
85
|
if (config.iface && iface !== config.iface) {
|
|
86
86
|
return;
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
-
Object.keys(this.ccu.metadata.devices[iface]).forEach(address => {
|
|
89
|
+
Object.keys(this.ccu.metadata.devices[iface]).forEach((address) => {
|
|
90
90
|
if (this.blacklist.has(address)) {
|
|
91
91
|
return;
|
|
92
92
|
}
|
|
@@ -130,12 +130,18 @@ module.exports = function (RED) {
|
|
|
130
130
|
return;
|
|
131
131
|
}
|
|
132
132
|
|
|
133
|
-
if (
|
|
133
|
+
if (
|
|
134
|
+
config.deviceNameRx === 'str' &&
|
|
135
|
+
this.ccu.channelNames[channel.PARENT] !== config.deviceName
|
|
136
|
+
) {
|
|
134
137
|
this.blacklist.add(address);
|
|
135
138
|
return;
|
|
136
139
|
}
|
|
137
140
|
|
|
138
|
-
if (
|
|
141
|
+
if (
|
|
142
|
+
config.deviceNameRx === 're' &&
|
|
143
|
+
!this.ccu.channelNames[channel.PARENT].match(new RegExp(config.deviceName))
|
|
144
|
+
) {
|
|
139
145
|
this.blacklist.add(address);
|
|
140
146
|
return;
|
|
141
147
|
}
|
|
@@ -171,7 +177,10 @@ module.exports = function (RED) {
|
|
|
171
177
|
return;
|
|
172
178
|
}
|
|
173
179
|
|
|
174
|
-
if (
|
|
180
|
+
if (
|
|
181
|
+
config.channelIndexRx === 're' &&
|
|
182
|
+
!address.split(':')[1].match(new RegExp(String(config.channelIndex)))
|
|
183
|
+
) {
|
|
175
184
|
this.blacklist.add(address);
|
|
176
185
|
return;
|
|
177
186
|
}
|
|
@@ -183,12 +192,18 @@ module.exports = function (RED) {
|
|
|
183
192
|
return;
|
|
184
193
|
}
|
|
185
194
|
|
|
186
|
-
if (
|
|
195
|
+
if (
|
|
196
|
+
config.channelNameRx === 'str' &&
|
|
197
|
+
this.ccu.channelNames[address] !== config.channelName
|
|
198
|
+
) {
|
|
187
199
|
this.blacklist.add(address);
|
|
188
200
|
return;
|
|
189
201
|
}
|
|
190
202
|
|
|
191
|
-
if (
|
|
203
|
+
if (
|
|
204
|
+
config.channelNameRx === 're' &&
|
|
205
|
+
!this.ccu.channelNames[address].match(new RegExp(config.channelName))
|
|
206
|
+
) {
|
|
192
207
|
this.blacklist.add(address);
|
|
193
208
|
return;
|
|
194
209
|
}
|
|
@@ -207,7 +222,7 @@ module.exports = function (RED) {
|
|
|
207
222
|
|
|
208
223
|
if (config.roomsRx === 're') {
|
|
209
224
|
let match = false;
|
|
210
|
-
this.ccu.channelRooms[address].forEach(room => {
|
|
225
|
+
this.ccu.channelRooms[address].forEach((room) => {
|
|
211
226
|
if (room.match(new RegExp(config.rooms))) {
|
|
212
227
|
match = true;
|
|
213
228
|
}
|
|
@@ -225,14 +240,17 @@ module.exports = function (RED) {
|
|
|
225
240
|
return;
|
|
226
241
|
}
|
|
227
242
|
|
|
228
|
-
if (
|
|
243
|
+
if (
|
|
244
|
+
config.functionsRx === 'str' &&
|
|
245
|
+
!this.ccu.channelFunctions[address].includes(config.functions)
|
|
246
|
+
) {
|
|
229
247
|
this.blacklist.add(address);
|
|
230
248
|
return;
|
|
231
249
|
}
|
|
232
250
|
|
|
233
251
|
if (config.functionsRx === 're') {
|
|
234
252
|
let match = false;
|
|
235
|
-
this.ccu.channelFunctions[address].forEach(func => {
|
|
253
|
+
this.ccu.channelFunctions[address].forEach((func) => {
|
|
236
254
|
if (func.match(new RegExp(config.functions))) {
|
|
237
255
|
match = true;
|
|
238
256
|
}
|
|
@@ -250,7 +268,7 @@ module.exports = function (RED) {
|
|
|
250
268
|
const psKey = this.ccu.paramsetName(iface, channel, 'VALUES');
|
|
251
269
|
if (this.ccu.paramsetDescriptions[psKey]) {
|
|
252
270
|
const rx = new RegExp(config.datapoint);
|
|
253
|
-
Object.keys(this.ccu.paramsetDescriptions[psKey]).forEach(dp => {
|
|
271
|
+
Object.keys(this.ccu.paramsetDescriptions[psKey]).forEach((dp) => {
|
|
254
272
|
if (config.datapointRx === 'str' && dp !== config.datapoint) {
|
|
255
273
|
return;
|
|
256
274
|
}
|
|
@@ -262,8 +280,14 @@ module.exports = function (RED) {
|
|
|
262
280
|
const datapointName = iface + '.' + address + '.' + dp;
|
|
263
281
|
const currentValue = this.ccu.values[datapointName] && this.ccu.values[datapointName].value;
|
|
264
282
|
count += 1;
|
|
265
|
-
if (
|
|
266
|
-
|
|
283
|
+
if (
|
|
284
|
+
dp.startsWith('PRESS_') ||
|
|
285
|
+
typeof currentValue === 'undefined' ||
|
|
286
|
+
currentValue !== message.payload
|
|
287
|
+
) {
|
|
288
|
+
this.ccu
|
|
289
|
+
.setValueQueued(iface, address, dp, message.payload, false, config.force)
|
|
290
|
+
.catch(() => {});
|
|
267
291
|
}
|
|
268
292
|
});
|
|
269
293
|
}
|
package/nodes/ccu-signal.html
CHANGED
|
@@ -151,6 +151,7 @@
|
|
|
151
151
|
|
|
152
152
|
let ifacesLoaded = false;
|
|
153
153
|
let ifacesPending = false;
|
|
154
|
+
let ifaceLoadRetries = 5;
|
|
154
155
|
|
|
155
156
|
function loadIfaces(iface, cb) {
|
|
156
157
|
if (ifacesPending) {
|
|
@@ -158,7 +159,6 @@
|
|
|
158
159
|
}
|
|
159
160
|
|
|
160
161
|
ifacesPending = true;
|
|
161
|
-
console.log('loadIfaces()');
|
|
162
162
|
$nodeInputIface.html('');
|
|
163
163
|
const nodeId = $nodeInputCcuConfig.val();
|
|
164
164
|
if (nodeId === '_ADD_') {
|
|
@@ -178,6 +178,12 @@
|
|
|
178
178
|
cb();
|
|
179
179
|
ifacesPending = false;
|
|
180
180
|
}
|
|
181
|
+
}).fail(() => {
|
|
182
|
+
// config node not (yet) available in the runtime - allow retrying
|
|
183
|
+
ifacesPending = false;
|
|
184
|
+
if (ifaceLoadRetries-- > 0) {
|
|
185
|
+
setTimeout(() => loadIfaces(iface, cb), 1000);
|
|
186
|
+
}
|
|
181
187
|
});
|
|
182
188
|
}
|
|
183
189
|
}
|
|
@@ -186,7 +192,6 @@
|
|
|
186
192
|
if (ifacesLoaded) {
|
|
187
193
|
const nodeId = $nodeInputCcuConfig.val();
|
|
188
194
|
if (nodeId && nodeId !== '__ADD__') {
|
|
189
|
-
console.log('loadConfig()');
|
|
190
195
|
$.getJSON('ccu?type=signal&config=' + nodeId + '&iface=' + $nodeInputIface.val(), d => {
|
|
191
196
|
data = d;
|
|
192
197
|
autoCompleteChannel();
|
|
@@ -198,7 +203,6 @@
|
|
|
198
203
|
}
|
|
199
204
|
|
|
200
205
|
$nodeInputCcuConfig.change(() => {
|
|
201
|
-
console.log('$nodeInputCcuConfig change');
|
|
202
206
|
loadIfaces(this.iface, () => {
|
|
203
207
|
ifacesLoaded = true;
|
|
204
208
|
$nodeInputIface.removeAttr('disabled');
|
|
@@ -206,6 +210,10 @@
|
|
|
206
210
|
});
|
|
207
211
|
});
|
|
208
212
|
|
|
213
|
+
// Node-RED 4.x does not reliably fire the change event on dialog
|
|
214
|
+
// open - trigger the initial load explicitly (see ROADMAP.md 8.1)
|
|
215
|
+
$nodeInputCcuConfig.trigger('change');
|
|
216
|
+
|
|
209
217
|
$nodeInputIface.change(() => {
|
|
210
218
|
if (ifacesLoaded) {
|
|
211
219
|
loadConfig();
|
|
@@ -258,7 +266,6 @@
|
|
|
258
266
|
});
|
|
259
267
|
}
|
|
260
268
|
|
|
261
|
-
console.log('autoCompleteChannel()', arr.length);
|
|
262
269
|
$nodeInputChannel.autocomplete('option', 'source', arr);
|
|
263
270
|
|
|
264
271
|
if (!data[$nodeInputChannel.val().split(' ')[0]]) {
|
|
@@ -417,7 +424,6 @@
|
|
|
417
424
|
$('#node-input-dimmer-container').editableList('items').each(function () {
|
|
418
425
|
dimmerList.push({color: $(this).find('select.color').val(), ontime: $(this).find('select.ontime').val()});
|
|
419
426
|
});
|
|
420
|
-
console.log(dimmerList);
|
|
421
427
|
this.dimmerList = dimmerList;
|
|
422
428
|
break;
|
|
423
429
|
}
|
package/nodes/ccu-signal.js
CHANGED
|
@@ -29,16 +29,19 @@ module.exports = function (RED) {
|
|
|
29
29
|
.then(() => this.getValue(values, 'repeat', message))
|
|
30
30
|
.then(() => this.getValue(values, 'volume', message))
|
|
31
31
|
.then(() => this.getValue(values, 'soundLevel', message))
|
|
32
|
-
.catch(error => {
|
|
32
|
+
.catch((error) => {
|
|
33
33
|
this.error(error.message);
|
|
34
34
|
})
|
|
35
35
|
.then(() => {
|
|
36
|
-
this.sendCommand({...this.config, ...values})
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
36
|
+
this.sendCommand({...this.config, ...values})
|
|
37
|
+
.then(() => {
|
|
38
|
+
done();
|
|
39
|
+
})
|
|
40
|
+
.catch((error) => {
|
|
41
|
+
done(error);
|
|
42
|
+
});
|
|
43
|
+
})
|
|
44
|
+
.catch(() => {});
|
|
42
45
|
});
|
|
43
46
|
}
|
|
44
47
|
|
|
@@ -56,12 +59,16 @@ module.exports = function (RED) {
|
|
|
56
59
|
payload = ['1', config.repeat, 108000, ...config.led.split(',')];
|
|
57
60
|
return this.ccu.setValue(config.iface, config.channel, 'SUBMIT', payload);
|
|
58
61
|
case 'ALARM_SWITCH_VIRTUAL_RECEIVER':
|
|
59
|
-
return this.ccu.methodCall(config.iface, 'putParamset', [
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
62
|
+
return this.ccu.methodCall(config.iface, 'putParamset', [
|
|
63
|
+
config.channel,
|
|
64
|
+
'VALUES',
|
|
65
|
+
{
|
|
66
|
+
ACOUSTIC_ALARM_SELECTION: config.acousticAlarmSelection,
|
|
67
|
+
DURATION_UNIT: config.durationUnit,
|
|
68
|
+
DURATION_VALUE: Number.parseInt(config.durationValue, 10) || 0,
|
|
69
|
+
OPTICAL_ALARM_SELECTION: config.opticalAlarmSelection,
|
|
70
|
+
},
|
|
71
|
+
]);
|
|
65
72
|
case 'DIMMER_VIRTUAL_RECEIVER': {
|
|
66
73
|
const parameters = {
|
|
67
74
|
LEVEL: config.dimmerLevel / 100,
|
|
@@ -70,7 +77,7 @@ module.exports = function (RED) {
|
|
|
70
77
|
DURATION_UNIT: config.durationUnit,
|
|
71
78
|
DURATION_VALUE: Number.parseInt(config.durationValue, 10) || 0,
|
|
72
79
|
REPETITIONS: Number(config.repetitions),
|
|
73
|
-
OUTPUT_SELECT_SIZE: config.dimmerList.length
|
|
80
|
+
OUTPUT_SELECT_SIZE: config.dimmerList.length,
|
|
74
81
|
};
|
|
75
82
|
config.dimmerList.forEach((item, i) => {
|
|
76
83
|
const index = i + 1;
|
|
@@ -81,14 +88,18 @@ module.exports = function (RED) {
|
|
|
81
88
|
}
|
|
82
89
|
|
|
83
90
|
case 'BSL_DIMMER_VIRTUAL_RECEIVER': {
|
|
84
|
-
return this.ccu.methodCall(config.iface, 'putParamset', [
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
91
|
+
return this.ccu.methodCall(config.iface, 'putParamset', [
|
|
92
|
+
config.channel,
|
|
93
|
+
'VALUES',
|
|
94
|
+
{
|
|
95
|
+
LEVEL: config.dimmerLevel / 100,
|
|
96
|
+
RAMP_TIME_UNIT: config.rampTimeUnit,
|
|
97
|
+
RAMP_TIME_VALUE: Number(config.rampTimeValue),
|
|
98
|
+
DURATION_UNIT: config.durationUnit,
|
|
99
|
+
DURATION_VALUE: Number.parseInt(config.durationValue, 10) || 0,
|
|
100
|
+
COLOR: Number(config.dimmerColor),
|
|
101
|
+
},
|
|
102
|
+
]);
|
|
92
103
|
}
|
|
93
104
|
|
|
94
105
|
case 'ACOUSTIC_SIGNAL_VIRTUAL_RECEIVER': {
|
|
@@ -99,7 +110,7 @@ module.exports = function (RED) {
|
|
|
99
110
|
DURATION_UNIT: config.durationUnit,
|
|
100
111
|
DURATION_VALUE: Number.parseInt(config.durationValue, 10) || 0,
|
|
101
112
|
REPETITIONS: Number(config.repetitions),
|
|
102
|
-
OUTPUT_SELECT_SIZE: config.soundList.length
|
|
113
|
+
OUTPUT_SELECT_SIZE: config.soundList.length,
|
|
103
114
|
};
|
|
104
115
|
config.soundList.forEach((item, i) => {
|
|
105
116
|
const index = i + 1;
|
package/nodes/ccu-switch.html
CHANGED
|
@@ -113,6 +113,7 @@
|
|
|
113
113
|
|
|
114
114
|
let ifacesLoaded = false;
|
|
115
115
|
let ifacesPending = false;
|
|
116
|
+
let ifaceLoadRetries = 5;
|
|
116
117
|
|
|
117
118
|
$('.form-row.datapoint').hide();
|
|
118
119
|
$('.form-row.sysvar').hide();
|
|
@@ -134,7 +135,6 @@
|
|
|
134
135
|
return;
|
|
135
136
|
}
|
|
136
137
|
ifacesPending = true;
|
|
137
|
-
console.log('loadIfaces()');
|
|
138
138
|
|
|
139
139
|
$nodeInputIface.html('');
|
|
140
140
|
|
|
@@ -154,6 +154,12 @@
|
|
|
154
154
|
cb();
|
|
155
155
|
ifacesPending = false;
|
|
156
156
|
}
|
|
157
|
+
}).fail(() => {
|
|
158
|
+
// config node not (yet) available in the runtime - allow retrying
|
|
159
|
+
ifacesPending = false;
|
|
160
|
+
if (ifaceLoadRetries-- > 0) {
|
|
161
|
+
setTimeout(() => loadIfaces(iface, cb), 1000);
|
|
162
|
+
}
|
|
157
163
|
});
|
|
158
164
|
$.getJSON('ccu?type=sysvar&config=' + nodeId, data => {
|
|
159
165
|
$nodeInputSysvar.html('');
|
|
@@ -163,6 +169,8 @@
|
|
|
163
169
|
});
|
|
164
170
|
}
|
|
165
171
|
});
|
|
172
|
+
} else {
|
|
173
|
+
ifacesPending = false;
|
|
166
174
|
}
|
|
167
175
|
}
|
|
168
176
|
|
|
@@ -170,7 +178,6 @@
|
|
|
170
178
|
if (!ifacesLoaded) {
|
|
171
179
|
return;
|
|
172
180
|
}
|
|
173
|
-
console.log('loadConfig()');
|
|
174
181
|
const nodeId = $nodeInputCcuConfig.val();
|
|
175
182
|
const url = 'ccu?config=' + nodeId + '&type=channels&iface=' + $nodeInputIface.val();
|
|
176
183
|
$.getJSON(url, d => {
|
|
@@ -181,13 +188,16 @@
|
|
|
181
188
|
}
|
|
182
189
|
|
|
183
190
|
$nodeInputCcuConfig.change(() => {
|
|
184
|
-
console.log('$nodeInputCcuConfig change');
|
|
185
191
|
loadIfaces(this.iface, () => {
|
|
186
192
|
ifacesLoaded = true;
|
|
187
193
|
loadConfig();
|
|
188
194
|
});
|
|
189
195
|
});
|
|
190
196
|
|
|
197
|
+
// Node-RED 4.x does not reliably fire the change event on dialog
|
|
198
|
+
// open - trigger the initial load explicitly (see ROADMAP.md 8.1)
|
|
199
|
+
$nodeInputCcuConfig.trigger('change');
|
|
200
|
+
|
|
191
201
|
$nodeInputChannel.autocomplete({
|
|
192
202
|
source: [],
|
|
193
203
|
close: () => {
|
|
@@ -247,7 +257,6 @@
|
|
|
247
257
|
}
|
|
248
258
|
|
|
249
259
|
$nodeInputIface.change(() => {
|
|
250
|
-
console.log('$nodeInputIface change');
|
|
251
260
|
if ($nodeInputIface.val() === 'ReGaHSS') {
|
|
252
261
|
$('.form-row.datapoint').hide();
|
|
253
262
|
$('.form-row.sysvar').show();
|
|
@@ -531,7 +540,6 @@
|
|
|
531
540
|
}
|
|
532
541
|
|
|
533
542
|
$configLookupTree.on('treelistselect', (event, item) => {
|
|
534
|
-
console.log(item);
|
|
535
543
|
if (item && item.iface && item.channel && item.datapoint && item.property) {
|
|
536
544
|
$('.form-row.sysvar').hide();
|
|
537
545
|
$('.form-row.datapoint').show();
|
package/nodes/ccu-sysvar.html
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
defaults: {
|
|
6
6
|
name: {value: ''},
|
|
7
7
|
ccuConfig: {value: 'localhost', type: 'ccu-connection', required: true},
|
|
8
|
-
topic: {value: 'ReGaHSS/${Name}'},
|
|
8
|
+
topic: {value: 'ReGaHSS/${Name}'},
|
|
9
9
|
change: {value: true},
|
|
10
10
|
cache: {value: true}
|
|
11
11
|
},
|
package/nodes/ccu-sysvar.js
CHANGED
|
@@ -28,11 +28,14 @@ module.exports = function (RED) {
|
|
|
28
28
|
this.name = config.name;
|
|
29
29
|
this.topic = config.topic;
|
|
30
30
|
|
|
31
|
-
this.idSubscription = this.ccu.subscribeSysvar(
|
|
32
|
-
|
|
33
|
-
message
|
|
34
|
-
|
|
35
|
-
|
|
31
|
+
this.idSubscription = this.ccu.subscribeSysvar(
|
|
32
|
+
{name: this.name, cache: config.cache, change: config.change},
|
|
33
|
+
(message) => {
|
|
34
|
+
this.status({fill: 'green', shape: 'ring', text: String(message.payload)});
|
|
35
|
+
message.topic = this.ccu.topicReplace(config.topic, message);
|
|
36
|
+
this.send(message);
|
|
37
|
+
},
|
|
38
|
+
);
|
|
36
39
|
|
|
37
40
|
this.on('input', this._input);
|
|
38
41
|
this.on('close', this._destructor);
|
|
@@ -41,12 +44,13 @@ module.exports = function (RED) {
|
|
|
41
44
|
_input(message, send, done) {
|
|
42
45
|
const name = this.name || message.topic;
|
|
43
46
|
const value = message.payload;
|
|
44
|
-
this.ccu
|
|
47
|
+
this.ccu
|
|
48
|
+
.setVariable(name, value)
|
|
45
49
|
.then(() => {
|
|
46
50
|
this.status({fill: 'green', shape: 'ring', text: String(value)});
|
|
47
51
|
done();
|
|
48
52
|
})
|
|
49
|
-
.catch(error => {
|
|
53
|
+
.catch((error) => {
|
|
50
54
|
this.currentStatus = 'red';
|
|
51
55
|
this.status({fill: 'red', shape: 'dot', text: 'error'});
|
|
52
56
|
done(error);
|