node-red-contrib-ccu 3.4.1 → 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 +43 -15
- package/nodes/ccu-connection.html +9 -1
- package/nodes/ccu-connection.js +602 -337
- package/nodes/ccu-display.html +11 -4
- package/nodes/ccu-display.js +26 -9
- package/nodes/ccu-get-value.html +23 -14
- package/nodes/ccu-get-value.js +10 -5
- 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 +47 -16
- package/nodes/ccu-signal.html +11 -5
- package/nodes/ccu-signal.js +34 -23
- package/nodes/ccu-switch.html +23 -13
- 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 -144
- 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
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"id": "sysvar-watch",
|
|
4
|
+
"type": "ccu-sysvar",
|
|
5
|
+
"name": "Presence",
|
|
6
|
+
"ccuConfig": "ccu-conn-example",
|
|
7
|
+
"topic": "${CCU}/SysVar/${Name}",
|
|
8
|
+
"change": true,
|
|
9
|
+
"cache": true,
|
|
10
|
+
"x": 340,
|
|
11
|
+
"y": 100,
|
|
12
|
+
"wires": [["debug-sysvar"]]
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"id": "debug-sysvar",
|
|
16
|
+
"type": "debug",
|
|
17
|
+
"name": "sysvar",
|
|
18
|
+
"active": true,
|
|
19
|
+
"tosidebar": true,
|
|
20
|
+
"complete": "payload",
|
|
21
|
+
"x": 550,
|
|
22
|
+
"y": 100,
|
|
23
|
+
"wires": []
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"id": "inject-set",
|
|
27
|
+
"type": "inject",
|
|
28
|
+
"name": "set true",
|
|
29
|
+
"props": [
|
|
30
|
+
{
|
|
31
|
+
"p": "payload"
|
|
32
|
+
}
|
|
33
|
+
],
|
|
34
|
+
"payload": "true",
|
|
35
|
+
"payloadType": "bool",
|
|
36
|
+
"x": 140,
|
|
37
|
+
"y": 100,
|
|
38
|
+
"wires": [["sysvar-watch"]]
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"id": "ccu-conn-example",
|
|
42
|
+
"type": "ccu-connection",
|
|
43
|
+
"name": "CCU",
|
|
44
|
+
"host": "ccu3-hostname-or-ip",
|
|
45
|
+
"regaEnabled": true,
|
|
46
|
+
"bcrfEnabled": true,
|
|
47
|
+
"iprfEnabled": true,
|
|
48
|
+
"virtEnabled": false,
|
|
49
|
+
"bcwiEnabled": false,
|
|
50
|
+
"cuxdEnabled": false,
|
|
51
|
+
"jackEnabled": false,
|
|
52
|
+
"regaPoll": true,
|
|
53
|
+
"regaInterval": "30",
|
|
54
|
+
"rpcPingTimeout": "60",
|
|
55
|
+
"rpcInitAddress": "",
|
|
56
|
+
"rpcServerHost": "",
|
|
57
|
+
"rpcBinPort": "2047",
|
|
58
|
+
"rpcXmlPort": "2048"
|
|
59
|
+
}
|
|
60
|
+
]
|
package/nodes/ccu-alexa.html
CHANGED
|
@@ -21,7 +21,6 @@
|
|
|
21
21
|
return this.name ? 'node_label_italic' : '';
|
|
22
22
|
},
|
|
23
23
|
oneditprepare() {
|
|
24
|
-
console.log(this);
|
|
25
24
|
|
|
26
25
|
const $nodeInputIface = $('#node-input-iface');
|
|
27
26
|
const $nodeInputCcuConfig = $('#node-input-ccuConfig');
|
|
@@ -30,6 +29,7 @@
|
|
|
30
29
|
let data;
|
|
31
30
|
let ifacesLoaded = false;
|
|
32
31
|
let ifacesPending = false;
|
|
32
|
+
let ifaceLoadRetries = 5;
|
|
33
33
|
|
|
34
34
|
function loadIfaces(iface, cb) {
|
|
35
35
|
if (ifacesPending) {
|
|
@@ -37,7 +37,6 @@
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
ifacesPending = true;
|
|
40
|
-
console.log('loadIfaces()');
|
|
41
40
|
$nodeInputIface.html('<option value=""></option>');
|
|
42
41
|
const nodeId = $nodeInputCcuConfig.val();
|
|
43
42
|
if (nodeId === '_ADD_') {
|
|
@@ -57,6 +56,12 @@
|
|
|
57
56
|
cb();
|
|
58
57
|
ifacesPending = false;
|
|
59
58
|
}
|
|
59
|
+
}).fail(() => {
|
|
60
|
+
// config node not (yet) available in the runtime - allow retrying
|
|
61
|
+
ifacesPending = false;
|
|
62
|
+
if (ifaceLoadRetries-- > 0) {
|
|
63
|
+
setTimeout(() => loadIfaces(iface, cb), 1000);
|
|
64
|
+
}
|
|
60
65
|
});
|
|
61
66
|
}
|
|
62
67
|
}
|
|
@@ -66,18 +71,15 @@
|
|
|
66
71
|
return;
|
|
67
72
|
}
|
|
68
73
|
|
|
69
|
-
console.log('loadConfig()');
|
|
70
74
|
const nodeId = $nodeInputCcuConfig.val();
|
|
71
75
|
const url = 'ccu?config=' + nodeId + '&type=channels&iface=' + $nodeInputIface.val();
|
|
72
76
|
$.getJSON(url, d => {
|
|
73
77
|
data = d;
|
|
74
|
-
console.log(d);
|
|
75
78
|
autocompleteChannel();
|
|
76
79
|
});
|
|
77
80
|
}
|
|
78
81
|
|
|
79
82
|
$nodeInputCcuConfig.change(() => {
|
|
80
|
-
console.log('$nodeInputCcuConfig change');
|
|
81
83
|
loadIfaces(this.iface, () => {
|
|
82
84
|
ifacesLoaded = true;
|
|
83
85
|
$nodeInputIface.removeAttr('disabled');
|
|
@@ -85,6 +87,10 @@
|
|
|
85
87
|
});
|
|
86
88
|
});
|
|
87
89
|
|
|
90
|
+
// Node-RED 4.x does not reliably fire the change event on dialog
|
|
91
|
+
// open - trigger the initial load explicitly (see ROADMAP.md 8.1)
|
|
92
|
+
$nodeInputCcuConfig.trigger('change');
|
|
93
|
+
|
|
88
94
|
$nodeInputChannel.autocomplete({
|
|
89
95
|
source: [],
|
|
90
96
|
close: () => {
|
|
@@ -122,7 +128,6 @@
|
|
|
122
128
|
}
|
|
123
129
|
|
|
124
130
|
$nodeInputIface.change(() => {
|
|
125
|
-
console.log('$nodeInputIface change');
|
|
126
131
|
loadConfig();
|
|
127
132
|
});
|
|
128
133
|
},
|
|
@@ -172,7 +177,7 @@
|
|
|
172
177
|
|
|
173
178
|
</script>
|
|
174
179
|
|
|
175
|
-
<script type="text/x-red" data-
|
|
180
|
+
<script type="text/x-red" data-help-name="ccu-alexa" lang="de">
|
|
176
181
|
<p>Homematic Geräte mit node-red-contrib-alexa-smart-home verbinden. Am Eingang den Node "alexa smart home v3"
|
|
177
182
|
anschließen, am Ausgang "alexa smart home v3 state".</p>
|
|
178
183
|
</script>
|
package/nodes/ccu-alexa.js
CHANGED
|
@@ -36,21 +36,21 @@ module.exports = function (RED) {
|
|
|
36
36
|
change: true,
|
|
37
37
|
stable: true,
|
|
38
38
|
iface: config.iface,
|
|
39
|
-
channel: String(config.channel).split(' ')[0]
|
|
39
|
+
channel: String(config.channel).split(' ')[0],
|
|
40
40
|
};
|
|
41
41
|
|
|
42
42
|
const payload = {
|
|
43
43
|
acknowledge: true,
|
|
44
|
-
state: {}
|
|
44
|
+
state: {},
|
|
45
45
|
};
|
|
46
46
|
|
|
47
|
-
this.idSubscription = this.ccu.subscribe(filter, message => {
|
|
47
|
+
this.idSubscription = this.ccu.subscribe(filter, (message) => {
|
|
48
48
|
let change = false;
|
|
49
49
|
switch (channelType) {
|
|
50
50
|
case 'SHUTTER_CONTACT':
|
|
51
51
|
case 'ROTARY_HANDLE_SENSOR':
|
|
52
52
|
if (message.datapoint === 'STATE') {
|
|
53
|
-
payload.state.contact = message.payload ? '
|
|
53
|
+
payload.state.contact = message.payload ? 'DETECTED' : 'NOT_DETECTED';
|
|
54
54
|
change = true;
|
|
55
55
|
}
|
|
56
56
|
|
|
@@ -145,18 +145,31 @@ module.exports = function (RED) {
|
|
|
145
145
|
return;
|
|
146
146
|
}
|
|
147
147
|
|
|
148
|
-
|
|
148
|
+
const keys = Object.keys(payload.state);
|
|
149
|
+
|
|
150
|
+
if (keys.length > 0) {
|
|
149
151
|
if (change) {
|
|
150
152
|
this.debug(JSON.stringify(payload));
|
|
151
|
-
this.
|
|
152
|
-
|
|
153
|
+
this.status({
|
|
154
|
+
fill: 'green',
|
|
155
|
+
shape: 'ring',
|
|
156
|
+
text: JSON.stringify(payload.state).replace(/^{/, '').replace(/}$/, ''),
|
|
157
|
+
});
|
|
158
|
+
keys.forEach((key) => {
|
|
159
|
+
const distinctPayload = {
|
|
160
|
+
acknowledge: true,
|
|
161
|
+
state: {},
|
|
162
|
+
};
|
|
163
|
+
distinctPayload.state[key] = payload.state[key];
|
|
164
|
+
this.send({payload: distinctPayload});
|
|
165
|
+
});
|
|
153
166
|
}
|
|
154
167
|
} else {
|
|
155
168
|
this.debug('empty state object');
|
|
156
169
|
}
|
|
157
170
|
});
|
|
158
171
|
|
|
159
|
-
this.on('input', message => {
|
|
172
|
+
this.on('input', (message) => {
|
|
160
173
|
this.debug('alexa > ' + JSON.stringify(message));
|
|
161
174
|
|
|
162
175
|
if (!this.iface) {
|
|
@@ -173,7 +186,12 @@ module.exports = function (RED) {
|
|
|
173
186
|
case 'TurnOn':
|
|
174
187
|
case 'TurnOff':
|
|
175
188
|
if (channelType.startsWith('DIMMER')) {
|
|
176
|
-
this.ccu.setValueQueued(
|
|
189
|
+
this.ccu.setValueQueued(
|
|
190
|
+
this.iface,
|
|
191
|
+
this.channel,
|
|
192
|
+
'LEVEL',
|
|
193
|
+
message.payload === 'ON' ? 1 : 0,
|
|
194
|
+
);
|
|
177
195
|
} else {
|
|
178
196
|
this.ccu.setValueQueued(this.iface, this.channel, 'STATE', message.payload === 'ON');
|
|
179
197
|
}
|
|
@@ -191,7 +209,12 @@ module.exports = function (RED) {
|
|
|
191
209
|
|
|
192
210
|
case 'AdjustBrightness':
|
|
193
211
|
if (channelType.startsWith('DIMMER')) {
|
|
194
|
-
this.ccu.setValueQueued(
|
|
212
|
+
this.ccu.setValueQueued(
|
|
213
|
+
this.iface,
|
|
214
|
+
this.channel,
|
|
215
|
+
'LEVEL',
|
|
216
|
+
(this.values.brightness + message.payload) / 100,
|
|
217
|
+
);
|
|
195
218
|
} else {
|
|
196
219
|
this.ccu.setValueQueued(this.iface, this.channel, 'STATE', message.payload > 0);
|
|
197
220
|
}
|
|
@@ -206,7 +229,12 @@ module.exports = function (RED) {
|
|
|
206
229
|
break;
|
|
207
230
|
|
|
208
231
|
case 'HEATING_CLIMATECONTROL_TRANSCEIVER':
|
|
209
|
-
this.ccu.setValueQueued(
|
|
232
|
+
this.ccu.setValueQueued(
|
|
233
|
+
this.iface,
|
|
234
|
+
this.channel,
|
|
235
|
+
'SET_POINT_TEMPERATURE',
|
|
236
|
+
message.payload,
|
|
237
|
+
);
|
|
210
238
|
break;
|
|
211
239
|
|
|
212
240
|
default:
|
|
@@ -226,10 +254,10 @@ module.exports = function (RED) {
|
|
|
226
254
|
|
|
227
255
|
break;
|
|
228
256
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
257
|
+
// Todo case 'SetColor':
|
|
258
|
+
// Todo case 'SetColorTemperature':
|
|
259
|
+
// Todo case 'AdjustTargetTemperature':
|
|
260
|
+
// todo case 'SetThermostatMode':
|
|
233
261
|
|
|
234
262
|
default:
|
|
235
263
|
this.warn('unknown command ' + message.command);
|
|
@@ -11,6 +11,8 @@
|
|
|
11
11
|
virtEnabled: {value: true},
|
|
12
12
|
bcwiEnabled: {value: false},
|
|
13
13
|
cuxdEnabled: {value: false},
|
|
14
|
+
jackEnabled: {value: false},
|
|
15
|
+
jackPort: {value: 2121},
|
|
14
16
|
|
|
15
17
|
regaPoll: {value: true},
|
|
16
18
|
regaInterval: {value: 30},
|
|
@@ -80,6 +82,7 @@
|
|
|
80
82
|
$('#node-config-input-virtEnabled').prop('checked', ccu.interfaces.VirtualDevices);
|
|
81
83
|
$('#node-config-input-bcwiEnabled').prop('checked', ccu.interfaces['BidCos-Wired']);
|
|
82
84
|
$('#node-config-input-cuxdEnabled').prop('checked', ccu.interfaces.CuXD);
|
|
85
|
+
$('#node-config-input-jackEnabled').prop('checked', ccu.interfaces['CCU-Jack']);
|
|
83
86
|
}
|
|
84
87
|
});
|
|
85
88
|
},
|
|
@@ -116,6 +119,8 @@
|
|
|
116
119
|
}
|
|
117
120
|
});
|
|
118
121
|
|
|
122
|
+
// called from the inline onclick attribute of the authentication checkbox
|
|
123
|
+
// eslint-disable-next-line no-unused-vars
|
|
119
124
|
function TLSSSL(){
|
|
120
125
|
if (document.getElementById('node-config-input-authentication').checked && !document.getElementById('node-config-input-tls').checked){
|
|
121
126
|
document.getElementById('node-config-input-tls').checked = true
|
|
@@ -168,7 +173,9 @@
|
|
|
168
173
|
<label class="ccu-checkbox"><input type="checkbox" id="node-config-input-bcwiEnabled"> BidCos-Wired</label><br>
|
|
169
174
|
<label class="ccu-checkbox"><input type="checkbox" id="node-config-input-iprfEnabled"> HmIP-RF</label><br>
|
|
170
175
|
<label class="ccu-checkbox"><input type="checkbox" id="node-config-input-virtEnabled"> VirtualDevices</label><br>
|
|
171
|
-
<label class="ccu-checkbox"><input type="checkbox" id="node-config-input-cuxdEnabled"> CUxD</label>
|
|
176
|
+
<label class="ccu-checkbox"><input type="checkbox" id="node-config-input-cuxdEnabled"> CUxD</label><br>
|
|
177
|
+
<label class="ccu-checkbox"><input type="checkbox" id="node-config-input-jackEnabled"> CCU-Jack</label>
|
|
178
|
+
<input type="text" id="node-config-input-jackPort" style="width: 70px;" placeholder="2121">
|
|
172
179
|
</div>
|
|
173
180
|
</div>
|
|
174
181
|
<div class="form-row">
|
|
@@ -254,6 +261,7 @@
|
|
|
254
261
|
<li>HmIP-RF: Homematic-IP Funk</li>
|
|
255
262
|
<li>VirtualDevices: Heizungsgruppen, in CCU eingebundene Systeme wie Osram Lightify</li>
|
|
256
263
|
<li>CUxD</li>
|
|
264
|
+
<li>CCU-Jack: XMLRPC-Schnittstelle des <a href="https://github.com/mdzio/ccu-jack" target="_blank">CCU-Jack</a> Addons (Port konfigurierbar, Standard 2121 bzw. 2122 mit TLS)</li>
|
|
257
265
|
</ul>
|
|
258
266
|
|
|
259
267
|
</li>
|