hm2mqtt 3.6.0 → 3.6.2
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/README.md +2 -2
- package/lib/hadiscovery.js +4 -1
- package/lib/rpc.js +31 -4
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -372,8 +372,8 @@ Same topics for events, variables, programs, counters, `set` and `paramset`. Dif
|
|
|
372
372
|
## Development
|
|
373
373
|
|
|
374
374
|
`npm test` (node:test, no CCU needed), `npm run lint`. `deploy.sh` ships the package (and
|
|
375
|
-
`file:../` siblings) to a host and restarts the `hm2mqtt@*` units. Plan and decisions:
|
|
376
|
-
|
|
375
|
+
`file:../` siblings) to a host and restarts the `hm2mqtt@*` units. Plan and decisions: the
|
|
376
|
+
roadmap, kept outside this repository; changes: [CHANGELOG.md](CHANGELOG.md).
|
|
377
377
|
|
|
378
378
|
## License
|
|
379
379
|
|
package/lib/hadiscovery.js
CHANGED
|
@@ -635,7 +635,10 @@ function deviceBlock({iface, device, list, ctx, t, st, cmd, bridgeId, ignored})
|
|
|
635
635
|
}
|
|
636
636
|
const avty = [...availability(name, 2)];
|
|
637
637
|
if (maintenance && maintenance.description.UNREACH && !ignored(iface, maintenance.ADDRESS, 'UNREACH')) {
|
|
638
|
-
|
|
638
|
+
// the template of an entry of an availability *list* is `val_tpl`; `avty_tpl` expands to
|
|
639
|
+
// `availability_template`, which Home Assistant's schema for such an entry does not allow
|
|
640
|
+
// - and it refuses the whole device payload over it (mqtt-interfaces-core 0.15.2)
|
|
641
|
+
avty.push({t: st(iface, maintenance.ADDRESS, 'UNREACH'), val_tpl: t.bool('offline', 'online')});
|
|
639
642
|
}
|
|
640
643
|
return {
|
|
641
644
|
id,
|
package/lib/rpc.js
CHANGED
|
@@ -22,6 +22,8 @@ export const METHODS = [
|
|
|
22
22
|
];
|
|
23
23
|
|
|
24
24
|
const TX_METHODS = new Set(['setValue', 'putParamset', 'activateLinkParamset']);
|
|
25
|
+
/** a failed init is retried after 2, 4, 8, 16 s, then every INIT_RETRY_MS (the cap) */
|
|
26
|
+
const INIT_BACKOFF_MS = [2000, 4000, 8000, 16000];
|
|
25
27
|
const INIT_RETRY_MS = 30000;
|
|
26
28
|
const DEINIT_TIMEOUT_MS = 1500;
|
|
27
29
|
const CALL_TIMEOUT_MS = 30000;
|
|
@@ -48,6 +50,15 @@ export function batchHints(events) {
|
|
|
48
50
|
return hints;
|
|
49
51
|
}
|
|
50
52
|
|
|
53
|
+
/**
|
|
54
|
+
* The delay before the next init attempt.
|
|
55
|
+
* @param {number} failures failed attempts in a row (1 after the first failure)
|
|
56
|
+
* @returns {number} ms
|
|
57
|
+
*/
|
|
58
|
+
export function initRetryDelay(failures) {
|
|
59
|
+
return failures >= 1 && failures <= INIT_BACKOFF_MS.length ? INIT_BACKOFF_MS[failures - 1] : INIT_RETRY_MS;
|
|
60
|
+
}
|
|
61
|
+
|
|
51
62
|
/**
|
|
52
63
|
* The callback servers the CCU talks to. One http (xmlrpc) and/or one binrpc server, started on
|
|
53
64
|
* demand; calls are routed by their init id to the registered RpcConnection.
|
|
@@ -288,6 +299,7 @@ export class RpcConnection extends EventEmitter {
|
|
|
288
299
|
this.initTimer = null;
|
|
289
300
|
this.pingTimer = null;
|
|
290
301
|
this.lastInitError = null;
|
|
302
|
+
this.initFailures = 0;
|
|
291
303
|
}
|
|
292
304
|
|
|
293
305
|
createClient() {
|
|
@@ -343,7 +355,7 @@ export class RpcConnection extends EventEmitter {
|
|
|
343
355
|
});
|
|
344
356
|
}
|
|
345
357
|
|
|
346
|
-
/** Connects: init subscription (retried
|
|
358
|
+
/** Connects: init subscription (retried with backoff from 2 s while it fails), ping supervision. */
|
|
347
359
|
async start() {
|
|
348
360
|
this.stopped = false;
|
|
349
361
|
if (!this.wantInit) {
|
|
@@ -372,18 +384,33 @@ export class RpcConnection extends EventEmitter {
|
|
|
372
384
|
this.log.info('rpc', this.name, '> init', url, this.initId);
|
|
373
385
|
await this.methodCall('init', [url, this.initId]);
|
|
374
386
|
this.initialized = true;
|
|
387
|
+
if (this.initFailures > 0) {
|
|
388
|
+
this.log.info('rpc', this.name, 'init succeeded after', this.initFailures + 1, 'attempts');
|
|
389
|
+
}
|
|
390
|
+
this.initFailures = 0;
|
|
375
391
|
this.lastInitError = null;
|
|
376
392
|
this.setConnected(true);
|
|
377
393
|
} catch (err) {
|
|
394
|
+
if (this.stopped) {
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
378
397
|
const msg = err.message || String(err);
|
|
398
|
+
this.initFailures += 1;
|
|
399
|
+
const delay = initRetryDelay(this.initFailures);
|
|
379
400
|
if (msg !== this.lastInitError) {
|
|
380
|
-
this.log.warn(
|
|
401
|
+
this.log.warn(
|
|
402
|
+
'rpc',
|
|
403
|
+
this.name,
|
|
404
|
+
'init failed:',
|
|
405
|
+
msg,
|
|
406
|
+
`- retrying in ${delay / 1000} s (then up to every ${INIT_RETRY_MS / 1000} s)`,
|
|
407
|
+
);
|
|
381
408
|
this.lastInitError = msg;
|
|
382
409
|
} else {
|
|
383
|
-
this.log.debug('rpc', this.name, 'init failed:', msg);
|
|
410
|
+
this.log.debug('rpc', this.name, 'init failed:', msg, `- next attempt in ${delay / 1000} s`);
|
|
384
411
|
}
|
|
385
412
|
this.setConnected(false);
|
|
386
|
-
this.initTimer = this.timers.setTimeout(() => this.init(),
|
|
413
|
+
this.initTimer = this.timers.setTimeout(() => this.init(), delay);
|
|
387
414
|
return;
|
|
388
415
|
}
|
|
389
416
|
if (this.wantPing) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hm2mqtt",
|
|
3
|
-
"version": "3.6.
|
|
3
|
+
"version": "3.6.2",
|
|
4
4
|
"description": "Interface between Homematic CCU and MQTT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
"binrpc": "^3.3.1",
|
|
71
71
|
"homematic-rega": "^2.0.0",
|
|
72
72
|
"homematic-xmlrpc": "^2.0.0",
|
|
73
|
-
"mqtt-interfaces-core": "^0.15.
|
|
73
|
+
"mqtt-interfaces-core": "^0.15.2"
|
|
74
74
|
},
|
|
75
75
|
"devDependencies": {
|
|
76
76
|
"@eslint/js": "^9.0.0",
|