node-red-contrib-ccu 4.4.2 → 4.4.3
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 +23 -0
- package/nodes/ccu-connection.js +53 -1
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,29 @@ Notable changes to node-red-contrib-ccu. Format follows
|
|
|
5
5
|
user-visible symptom and the cause, not the commit list (the release notes
|
|
6
6
|
append commits automatically).
|
|
7
7
|
|
|
8
|
+
## 4.4.3 (2026-09-09)
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- **Node-RED at 100 % CPU and unresponsive on openccu-lite** (B-27, found on
|
|
13
|
+
the maintainer's Pi 4 with RedMatic 9.4.2). openccu-lite has no ReGaHSS, so
|
|
14
|
+
nothing listens on port 31999 — but the connection node still created the
|
|
15
|
+
ReGaHSS binrpc client in metadata mode, and binrpc up to 4.2.0 armed a new
|
|
16
|
+
reconnect timer for both the `error` and the `close` event of every refused
|
|
17
|
+
connect, so the number of attempts doubled every 2.5 s without bound: about
|
|
18
|
+
7,000 refused connects per second, 30,000 pending timers and 68 million
|
|
19
|
+
connects in under three hours. The same explosion hit a CCU whenever its
|
|
20
|
+
ReGaHSS was down for a while (restart, backup restore); it just ended when
|
|
21
|
+
the port came back. Two changes: the ReGaHSS client is not created at all
|
|
22
|
+
while the box is an openccu-lite (and is closed when a box becomes one, or
|
|
23
|
+
created when it stops being one), and this release requires
|
|
24
|
+
[binrpc 4.3.0](https://github.com/hobbyquaker/binrpc/blob/master/CHANGELOG.md),
|
|
25
|
+
which keeps a single reconnect timer per client with exponential backoff
|
|
26
|
+
(2.5 s doubling to 30 s) and has `close()`. The connection node now closes
|
|
27
|
+
its rpc clients when it is removed or redeployed, and when it replaces a
|
|
28
|
+
client after a failed call — a replaced binrpc client used to keep
|
|
29
|
+
reconnecting in the background for the life of the process.
|
|
30
|
+
|
|
8
31
|
## 4.4.2 (2026-09-09)
|
|
9
32
|
|
|
10
33
|
### Fixed
|
package/nodes/ccu-connection.js
CHANGED
|
@@ -1151,6 +1151,13 @@ module.exports = function (RED) {
|
|
|
1151
1151
|
this.metaMode = true;
|
|
1152
1152
|
this.lastMetaProbe = now();
|
|
1153
1153
|
clearTimeout(this.regaPollTimeout);
|
|
1154
|
+
if (this.clients.ReGaHSS) {
|
|
1155
|
+
// the box became an openccu-lite while Node-RED was running
|
|
1156
|
+
// (recheckMeta): no ReGaHSS to talk to any more (B-27)
|
|
1157
|
+
this.logger.info('rpc client ReGaHSS closed: openccu-lite has no ReGaHSS');
|
|
1158
|
+
this.closeClient('ReGaHSS');
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1154
1161
|
this.logger.info(
|
|
1155
1162
|
'openccu-lite detected (' +
|
|
1156
1163
|
(info.implementation || 'meta api') +
|
|
@@ -1205,6 +1212,10 @@ module.exports = function (RED) {
|
|
|
1205
1212
|
return this.startMeta(again);
|
|
1206
1213
|
}
|
|
1207
1214
|
|
|
1215
|
+
if (this.ifaceTypes.ReGaHSS.enabled && !this.clients.ReGaHSS) {
|
|
1216
|
+
this.createClient('ReGaHSS').then(() => this.setIfaceStatus('ReGaHSS', true));
|
|
1217
|
+
}
|
|
1218
|
+
|
|
1208
1219
|
return this.getRegaData().then(() => this.regaPoll());
|
|
1209
1220
|
});
|
|
1210
1221
|
},
|
|
@@ -1868,6 +1879,16 @@ module.exports = function (RED) {
|
|
|
1868
1879
|
Object.keys(this.ifaceTypes).forEach((iface) => {
|
|
1869
1880
|
const enabled = config[this.ifaceTypes[iface].conf + 'Enabled'];
|
|
1870
1881
|
this.ifaceTypes[iface].enabled = enabled;
|
|
1882
|
+
if (enabled && iface === 'ReGaHSS' && this.metaMode) {
|
|
1883
|
+
// B-27: openccu-lite has no ReGaHSS, nothing listens on 31999.
|
|
1884
|
+
// A client would only reconnect forever (with binrpc < 4.3.0
|
|
1885
|
+
// exponentially, at 100 % CPU). The metadata api reports the
|
|
1886
|
+
// interface status instead; the client is created if the box
|
|
1887
|
+
// stops being an openccu-lite (onGone).
|
|
1888
|
+
this.logger.info('rpc client ReGaHSS not created: openccu-lite has no ReGaHSS');
|
|
1889
|
+
return;
|
|
1890
|
+
}
|
|
1891
|
+
|
|
1871
1892
|
if (enabled) {
|
|
1872
1893
|
this.createClient(iface)
|
|
1873
1894
|
.then(() => {
|
|
@@ -1896,6 +1917,28 @@ module.exports = function (RED) {
|
|
|
1896
1917
|
* @param iface
|
|
1897
1918
|
* @returns {Promise<any>}
|
|
1898
1919
|
*/
|
|
1920
|
+
/**
|
|
1921
|
+
* Drop an rpc client and stop its reconnect timer (binrpc >= 4.3.0 has
|
|
1922
|
+
* close(); the xmlrpc client holds no timer). Without this a replaced
|
|
1923
|
+
* client kept reconnecting in the background for the life of the process.
|
|
1924
|
+
* @param iface
|
|
1925
|
+
*/
|
|
1926
|
+
closeClient(iface) {
|
|
1927
|
+
const client = this.clients[iface];
|
|
1928
|
+
if (!client) {
|
|
1929
|
+
return;
|
|
1930
|
+
}
|
|
1931
|
+
|
|
1932
|
+
delete this.clients[iface];
|
|
1933
|
+
if (typeof client.close === 'function') {
|
|
1934
|
+
try {
|
|
1935
|
+
client.close();
|
|
1936
|
+
} catch (error) {
|
|
1937
|
+
this.logger.debug('close rpc client ' + iface + ': ' + error.message);
|
|
1938
|
+
}
|
|
1939
|
+
}
|
|
1940
|
+
}
|
|
1941
|
+
|
|
1899
1942
|
createClient(iface) {
|
|
1900
1943
|
return new Promise((resolve) => {
|
|
1901
1944
|
const {rpc, port, path, protocol, auth, user, pass, tls, inSecure} = this.ifaceTypes[iface];
|
|
@@ -2166,6 +2209,15 @@ module.exports = function (RED) {
|
|
|
2166
2209
|
});
|
|
2167
2210
|
});
|
|
2168
2211
|
|
|
2212
|
+
// last: the clients themselves, so their reconnect timers die with the
|
|
2213
|
+
// node (a redeploy used to leave every binrpc client reconnecting)
|
|
2214
|
+
calls.push(() => {
|
|
2215
|
+
Object.keys(this.clients).forEach((iface) => {
|
|
2216
|
+
this.closeClient(iface);
|
|
2217
|
+
});
|
|
2218
|
+
return Promise.resolve();
|
|
2219
|
+
});
|
|
2220
|
+
|
|
2169
2221
|
this.logger.debug('shutdown tasks: ' + calls.length);
|
|
2170
2222
|
return calls.reduce((p, task) => p.then(task), Promise.resolve());
|
|
2171
2223
|
}
|
|
@@ -3159,7 +3211,7 @@ module.exports = function (RED) {
|
|
|
3159
3211
|
this.clients[iface].methodCall(method, parameters, (err, res) => {
|
|
3160
3212
|
if (err) {
|
|
3161
3213
|
this.logger.error(' <', iface, method, err);
|
|
3162
|
-
|
|
3214
|
+
this.closeClient(iface);
|
|
3163
3215
|
this.createClient(iface);
|
|
3164
3216
|
reject(err);
|
|
3165
3217
|
} else if (res && res.faultCode) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-red-contrib-ccu",
|
|
3
|
-
"version": "4.4.
|
|
3
|
+
"version": "4.4.3",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"main": "none",
|
|
6
6
|
"keywords": [
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
}
|
|
51
51
|
],
|
|
52
52
|
"dependencies": {
|
|
53
|
-
"binrpc": "^4.
|
|
53
|
+
"binrpc": "^4.3.0",
|
|
54
54
|
"homematic-rega": "^2.0.1",
|
|
55
55
|
"homematic-xmlrpc": "^2.0.0",
|
|
56
56
|
"mqtt-wildcard": "^3.0.9"
|
|
@@ -75,7 +75,7 @@
|
|
|
75
75
|
"overrides": {
|
|
76
76
|
"hm-simulator": {
|
|
77
77
|
"homematic-xmlrpc": "^2.0.0",
|
|
78
|
-
"binrpc": "^4.
|
|
78
|
+
"binrpc": "^4.3.0"
|
|
79
79
|
}
|
|
80
80
|
},
|
|
81
81
|
"engines": {
|