matterbridge 1.4.3 → 1.5.1
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 +47 -0
- package/README-ADVANCED.md +197 -0
- package/README-DEV.md +167 -0
- package/README.md +26 -318
- package/dist/cluster/export.d.ts +23 -0
- package/dist/cluster/export.d.ts.map +1 -0
- package/dist/cluster/export.js +23 -0
- package/dist/cluster/export.js.map +1 -0
- package/dist/index.d.ts +0 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/matterbridge.d.ts +4 -1
- package/dist/matterbridge.d.ts.map +1 -1
- package/dist/matterbridge.js +149 -100
- package/dist/matterbridge.js.map +1 -1
- package/dist/matterbridgeDevice.d.ts +190 -114
- package/dist/matterbridgeDevice.d.ts.map +1 -1
- package/dist/matterbridgeDevice.js +379 -189
- package/dist/matterbridgeDevice.js.map +1 -1
- package/dist/matterbridgeTypes.d.ts +2 -0
- package/dist/matterbridgeTypes.d.ts.map +1 -1
- package/dist/pluginManager.d.ts.map +1 -1
- package/dist/pluginManager.js +13 -3
- package/dist/pluginManager.js.map +1 -1
- package/dist/utils/utils.d.ts +22 -3
- package/dist/utils/utils.d.ts.map +1 -1
- package/dist/utils/utils.js +106 -42
- package/dist/utils/utils.js.map +1 -1
- package/frontend/build/asset-manifest.json +5 -5
- package/frontend/build/index.html +1 -1
- package/frontend/build/static/js/453.abd36b29.chunk.js +2 -0
- package/frontend/build/static/js/{453.d855a71b.chunk.js.map → 453.abd36b29.chunk.js.map} +1 -1
- package/frontend/build/static/js/main.4c5271fd.js +3 -0
- package/frontend/build/static/js/main.4c5271fd.js.map +1 -0
- package/package.json +16 -15
- package/frontend/build/static/js/453.d855a71b.chunk.js +0 -2
- package/frontend/build/static/js/main.e76dd8f6.js +0 -3
- package/frontend/build/static/js/main.e76dd8f6.js.map +0 -1
- /package/frontend/build/static/js/{main.e76dd8f6.js.LICENSE.txt → main.4c5271fd.js.LICENSE.txt} +0 -0
package/dist/matterbridge.js
CHANGED
|
@@ -20,8 +20,7 @@
|
|
|
20
20
|
* See the License for the specific language governing permissions and
|
|
21
21
|
* limitations under the License. *
|
|
22
22
|
*/
|
|
23
|
-
|
|
24
|
-
import { AnsiLogger, UNDERLINE, UNDERLINEOFF, YELLOW, db, debugStringify, stringify, BRIGHT, RESET, er, nf, rs, wr, RED, GREEN, zb, hk, or, idn, BLUE, CYAN, nt } from 'node-ansi-logger';
|
|
23
|
+
// Node.js modules
|
|
25
24
|
import { fileURLToPath } from 'url';
|
|
26
25
|
import { promises as fs } from 'fs';
|
|
27
26
|
import { exec, spawn } from 'child_process';
|
|
@@ -32,10 +31,13 @@ import express from 'express';
|
|
|
32
31
|
import os from 'os';
|
|
33
32
|
import path from 'path';
|
|
34
33
|
import WebSocket, { WebSocketServer } from 'ws';
|
|
34
|
+
// NodeStorage and AnsiLogger modules
|
|
35
|
+
import { NodeStorageManager } from 'node-persist-manager';
|
|
36
|
+
import { AnsiLogger, UNDERLINE, UNDERLINEOFF, YELLOW, db, debugStringify, stringify, BRIGHT, RESET, er, nf, rs, wr, RED, GREEN, zb, hk, or, idn, BLUE, CYAN, nt } from 'node-ansi-logger';
|
|
35
37
|
// Matterbridge
|
|
36
38
|
import { MatterbridgeDevice } from './matterbridgeDevice.js';
|
|
37
39
|
import { BridgedDeviceBasicInformation, BridgedDeviceBasicInformationCluster } from './cluster/BridgedDeviceBasicInformationCluster.js';
|
|
38
|
-
import { logInterfaces, wait, waiter,
|
|
40
|
+
import { logInterfaces, wait, waiter, createZip } from './utils/utils.js';
|
|
39
41
|
// @project-chip/matter-node.js
|
|
40
42
|
import { CommissioningController, CommissioningServer, MatterServer } from '@project-chip/matter-node.js';
|
|
41
43
|
import { BasicInformationCluster, ClusterServer, FixedLabelCluster, GeneralCommissioning, PowerSourceCluster, SwitchCluster, ThreadNetworkDiagnosticsCluster, getClusterNameById } from '@project-chip/matter-node.js/cluster';
|
|
@@ -44,7 +46,7 @@ import { Aggregator, DeviceTypes, NodeStateInformation } from '@project-chip/mat
|
|
|
44
46
|
import { Format, Level, Logger } from '@project-chip/matter-node.js/log';
|
|
45
47
|
import { ManualPairingCodeCodec, QrCodeSchema } from '@project-chip/matter-node.js/schema';
|
|
46
48
|
import { StorageBackendDisk, StorageBackendJsonFile, StorageManager } from '@project-chip/matter-node.js/storage';
|
|
47
|
-
import {
|
|
49
|
+
import { getParameter, getIntParameter, hasParameter } from '@project-chip/matter-node.js/util';
|
|
48
50
|
import { CryptoNode } from '@project-chip/matter-node.js/crypto';
|
|
49
51
|
import { PluginManager } from './pluginManager.js';
|
|
50
52
|
import { DeviceManager } from './deviceManager.js';
|
|
@@ -80,6 +82,8 @@ export class Matterbridge extends EventEmitter {
|
|
|
80
82
|
globalModulesDirectory: '',
|
|
81
83
|
matterbridgeVersion: '',
|
|
82
84
|
matterbridgeLatestVersion: '',
|
|
85
|
+
matterbridgeQrPairingCode: undefined,
|
|
86
|
+
matterbridgeManualPairingCode: undefined,
|
|
83
87
|
matterbridgeFabricInformations: [],
|
|
84
88
|
matterbridgeSessionInformations: [],
|
|
85
89
|
matterbridgePaired: false,
|
|
@@ -98,14 +102,14 @@ export class Matterbridge extends EventEmitter {
|
|
|
98
102
|
globalModulesDirectory = '';
|
|
99
103
|
matterbridgeVersion = '';
|
|
100
104
|
matterbridgeLatestVersion = '';
|
|
105
|
+
matterbridgeQrPairingCode = undefined;
|
|
106
|
+
matterbridgeManualPairingCode = undefined;
|
|
101
107
|
matterbridgeFabricInformations = [];
|
|
102
108
|
matterbridgeSessionInformations = [];
|
|
103
109
|
matterbridgePaired = false;
|
|
104
110
|
matterbridgeConnected = false;
|
|
105
111
|
bridgeMode = '';
|
|
106
112
|
restartMode = '';
|
|
107
|
-
// public debugEnabled = false;
|
|
108
|
-
// public loggerLevel: LogLevel = LogLevel.INFO;
|
|
109
113
|
profile = getParameter('profile');
|
|
110
114
|
log;
|
|
111
115
|
matterbrideLoggerFile = 'matterbridge' + (getParameter('profile') ? '.' + getParameter('profile') : '') + '.log';
|
|
@@ -121,6 +125,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
121
125
|
hasCleanupStarted = false;
|
|
122
126
|
initialized = false;
|
|
123
127
|
execRunningCount = 0;
|
|
128
|
+
startMatterInterval;
|
|
124
129
|
cleanupTimeout1;
|
|
125
130
|
cleanupTimeout2;
|
|
126
131
|
checkUpdateInterval;
|
|
@@ -210,14 +215,19 @@ export class Matterbridge extends EventEmitter {
|
|
|
210
215
|
// Set the matterbridge directory
|
|
211
216
|
this.homeDirectory = os.homedir();
|
|
212
217
|
this.matterbridgeDirectory = path.join(this.homeDirectory, '.matterbridge');
|
|
213
|
-
//
|
|
214
|
-
|
|
218
|
+
// Initialize nodeStorage and nodeContext
|
|
219
|
+
// this.log.debug(`Creating node storage manager: ${CYAN}${this.nodeStorageName}${db}`);
|
|
220
|
+
this.nodeStorage = new NodeStorageManager({ dir: path.join(this.matterbridgeDirectory, this.nodeStorageName), writeQueue: false, expiredInterval: undefined, logging: false });
|
|
221
|
+
// this.log.debug('Creating node storage context for matterbridge');
|
|
222
|
+
this.nodeContext = await this.nodeStorage.createStorage('matterbridge');
|
|
223
|
+
// Create matterbridge logger
|
|
224
|
+
this.log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: "info" /* LogLevel.INFO */ });
|
|
225
|
+
// Create the file logger for matterbridge (context: matterbridgeFileLog)
|
|
226
|
+
if (hasParameter('filelogger') || (await this.nodeContext.get('matterbridgeFileLog', false))) {
|
|
215
227
|
AnsiLogger.setGlobalLogfile(path.join(this.matterbridgeDirectory, this.matterbrideLoggerFile), "debug" /* LogLevel.DEBUG */, true);
|
|
216
228
|
this.matterbridgeInformation.fileLogger = true;
|
|
217
229
|
}
|
|
218
|
-
//
|
|
219
|
-
this.log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: "info" /* LogLevel.INFO */ });
|
|
220
|
-
// Set matterbridge logger level
|
|
230
|
+
// Set matterbridge logger level (context: matterbridgeLogLevel)
|
|
221
231
|
if (hasParameter('logger')) {
|
|
222
232
|
const level = getParameter('logger');
|
|
223
233
|
if (level === 'debug') {
|
|
@@ -244,11 +254,12 @@ export class Matterbridge extends EventEmitter {
|
|
|
244
254
|
}
|
|
245
255
|
}
|
|
246
256
|
else {
|
|
247
|
-
this.log.logLevel = "info" /* LogLevel.INFO
|
|
257
|
+
this.log.logLevel = await this.nodeContext.get('matterbridgeLogLevel', "info" /* LogLevel.INFO */);
|
|
248
258
|
}
|
|
249
259
|
MatterbridgeDevice.logLevel = this.log.logLevel;
|
|
250
260
|
this.log.debug('Matterbridge is starting...');
|
|
251
|
-
|
|
261
|
+
this.log.debug(`Matterbridge logLevel: ${this.log.logLevel} fileLoger: ${this.matterbridgeInformation.fileLogger}.`);
|
|
262
|
+
// Set matter.js logger level, format and logger (context: matterLogLevel)
|
|
252
263
|
if (hasParameter('matterlogger')) {
|
|
253
264
|
const level = getParameter('matterlogger');
|
|
254
265
|
if (level === 'debug') {
|
|
@@ -275,30 +286,19 @@ export class Matterbridge extends EventEmitter {
|
|
|
275
286
|
}
|
|
276
287
|
}
|
|
277
288
|
else {
|
|
278
|
-
Logger.defaultLogLevel = Level.INFO;
|
|
289
|
+
Logger.defaultLogLevel = await this.nodeContext.get('matterLogLevel', Level.INFO);
|
|
279
290
|
}
|
|
280
291
|
Logger.format = Format.ANSI;
|
|
281
292
|
Logger.setLogger('default', this.createMatterLogger());
|
|
282
|
-
// Create the file logger for matter.js
|
|
283
|
-
if (hasParameter('matterfilelogger')) {
|
|
293
|
+
// Create the file logger for matter.js (context: matterFileLog)
|
|
294
|
+
if (hasParameter('matterfilelogger') || (await this.nodeContext.get('matterFileLog', false))) {
|
|
284
295
|
this.matterbridgeInformation.matterFileLogger = true;
|
|
285
|
-
/*
|
|
286
|
-
try {
|
|
287
|
-
await fs.unlink(path.join(this.matterbridgeDirectory, this.matterLoggerFile));
|
|
288
|
-
} catch (error) {
|
|
289
|
-
this.log.debug(`Error unlinking the log file ${CYAN}${path.join(this.matterbridgeDirectory, this.matterLoggerFile)}${er}: ${error instanceof Error ? error.message : error}`);
|
|
290
|
-
}
|
|
291
|
-
*/
|
|
292
296
|
Logger.addLogger('matterfilelogger', await this.createMatterFileLogger(path.join(this.matterbridgeDirectory, this.matterLoggerFile), true), {
|
|
293
297
|
defaultLogLevel: Level.DEBUG,
|
|
294
298
|
logFormat: Format.PLAIN,
|
|
295
299
|
});
|
|
296
300
|
}
|
|
297
|
-
|
|
298
|
-
this.log.debug(`Creating node storage manager: ${CYAN}${this.nodeStorageName}${db}`);
|
|
299
|
-
this.nodeStorage = new NodeStorageManager({ dir: path.join(this.matterbridgeDirectory, this.nodeStorageName), writeQueue: false, expiredInterval: undefined, logging: false });
|
|
300
|
-
this.log.debug('Creating node storage context for matterbridge');
|
|
301
|
-
this.nodeContext = await this.nodeStorage.createStorage('matterbridge');
|
|
301
|
+
this.log.debug(`Matter logLevel: ${Logger.defaultLogLevel} fileLoger: ${this.matterbridgeInformation.matterFileLogger}.`);
|
|
302
302
|
// Initialize PluginManager
|
|
303
303
|
this.plugins = new PluginManager(this);
|
|
304
304
|
await this.plugins.loadFromStorage();
|
|
@@ -307,8 +307,9 @@ export class Matterbridge extends EventEmitter {
|
|
|
307
307
|
// Get the plugins from node storage and create the plugins node storage contexts
|
|
308
308
|
for (const plugin of this.plugins) {
|
|
309
309
|
const packageJson = await this.plugins.parse(plugin);
|
|
310
|
-
if (packageJson === null) {
|
|
310
|
+
if (packageJson === null && !hasParameter('add')) {
|
|
311
311
|
// Try to reinstall the plugin from npm (for Docker pull and external plugins)
|
|
312
|
+
// We don't do this when the add parameter is set because we shut down the process after adding the plugin
|
|
312
313
|
this.log.info(`Error parsing plugin ${plg}${plugin.name}${nf}. Trying to reinstall it from npm.`);
|
|
313
314
|
try {
|
|
314
315
|
await this.spawnCommand('npm', ['install', '-g', plugin.name]);
|
|
@@ -333,10 +334,20 @@ export class Matterbridge extends EventEmitter {
|
|
|
333
334
|
}
|
|
334
335
|
// Log system info and create .matterbridge directory
|
|
335
336
|
await this.logNodeAndSystemInfo();
|
|
336
|
-
this.log.notice(`Matterbridge version ${this.matterbridgeVersion}
|
|
337
|
-
`${
|
|
337
|
+
this.log.notice(`Matterbridge version ${this.matterbridgeVersion} ` +
|
|
338
|
+
`${hasParameter('bridge') || (!hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'bridge') ? 'mode bridge ' : ''}` +
|
|
339
|
+
`${hasParameter('childbridge') || (!hasParameter('bridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'childbridge') ? 'mode childbridge ' : ''}` +
|
|
340
|
+
`${hasParameter('controller') ? 'mode controller ' : ''}` +
|
|
341
|
+
`${this.restartMode !== '' ? 'restart mode ' + this.restartMode + ' ' : ''}` +
|
|
342
|
+
`running on ${this.systemInformation.osType} (v.${this.systemInformation.osRelease}) platform ${this.systemInformation.osPlatform} arch ${this.systemInformation.osArch}`);
|
|
338
343
|
// Check node version and throw error
|
|
339
|
-
|
|
344
|
+
const minNodeVersion = 18;
|
|
345
|
+
const nodeVersion = process.versions.node;
|
|
346
|
+
const versionMajor = parseInt(nodeVersion.split('.')[0]);
|
|
347
|
+
if (versionMajor < minNodeVersion) {
|
|
348
|
+
this.log.error(`Node version ${versionMajor} is not supported. Please upgrade to ${minNodeVersion} or above.`);
|
|
349
|
+
throw new Error(`Node version ${versionMajor} is not supported. Please upgrade to ${minNodeVersion} or above.`);
|
|
350
|
+
}
|
|
340
351
|
// Register SIGINT SIGTERM signal handlers
|
|
341
352
|
this.registerSignalHandlers();
|
|
342
353
|
// Parse command line
|
|
@@ -357,6 +368,8 @@ export class Matterbridge extends EventEmitter {
|
|
|
357
368
|
- childbridge: start Matterbridge in childbridge mode
|
|
358
369
|
- port [port]: start the commissioning server on the given port (default 5540)
|
|
359
370
|
- mdnsinterface [name]: set the interface to use for the matter server mdnsInterface (default all interfaces)
|
|
371
|
+
- ipv4address [address]: set the ipv4 interface address to use for the matter listener (default all interfaces)
|
|
372
|
+
- ipv6address [address]: set the ipv6 interface address to use for the matter listener (default all interfaces)
|
|
360
373
|
- frontend [port]: start the frontend on the given port (default 8283)
|
|
361
374
|
- logger: set the matterbridge logger level: debug | info | notice | warn | error | fatal (default info)
|
|
362
375
|
- matterlogger: set the matter.js logger level: debug | info | notice | warn | error | fatal (default info)
|
|
@@ -517,8 +530,8 @@ export class Matterbridge extends EventEmitter {
|
|
|
517
530
|
}
|
|
518
531
|
}, 60 * 60 * 1000);
|
|
519
532
|
if (hasParameter('test')) {
|
|
520
|
-
this.bridgeMode = '
|
|
521
|
-
MatterbridgeDevice.bridgeMode = '
|
|
533
|
+
this.bridgeMode = 'bridge';
|
|
534
|
+
MatterbridgeDevice.bridgeMode = 'bridge';
|
|
522
535
|
await this.startTest();
|
|
523
536
|
return;
|
|
524
537
|
}
|
|
@@ -527,7 +540,12 @@ export class Matterbridge extends EventEmitter {
|
|
|
527
540
|
await this.startController();
|
|
528
541
|
return;
|
|
529
542
|
}
|
|
530
|
-
if
|
|
543
|
+
// Check if the bridge mode is set and start matterbridge in bridge mode if not set
|
|
544
|
+
if (!hasParameter('bridge') && !hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === '') {
|
|
545
|
+
this.log.info('Setting default matterbridge start mode to bridge');
|
|
546
|
+
await this.nodeContext?.set('bridgeMode', 'bridge');
|
|
547
|
+
}
|
|
548
|
+
if (hasParameter('bridge') || (!hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'bridge')) {
|
|
531
549
|
this.bridgeMode = 'bridge';
|
|
532
550
|
MatterbridgeDevice.bridgeMode = 'bridge';
|
|
533
551
|
if (!this.storageManager)
|
|
@@ -568,12 +586,12 @@ export class Matterbridge extends EventEmitter {
|
|
|
568
586
|
plugin.addedDevices = undefined;
|
|
569
587
|
plugin.qrPairingCode = undefined;
|
|
570
588
|
plugin.manualPairingCode = undefined;
|
|
571
|
-
this.plugins.load(plugin, true, 'Matterbridge is starting'); //
|
|
589
|
+
this.plugins.load(plugin, true, 'Matterbridge is starting'); // No await do it asyncronously
|
|
572
590
|
}
|
|
573
591
|
await this.startBridge();
|
|
574
592
|
return;
|
|
575
593
|
}
|
|
576
|
-
if (hasParameter('childbridge')) {
|
|
594
|
+
if (hasParameter('childbridge') || (!hasParameter('bridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'childbridge')) {
|
|
577
595
|
this.bridgeMode = 'childbridge';
|
|
578
596
|
MatterbridgeDevice.bridgeMode = 'childbridge';
|
|
579
597
|
if (!this.storageManager)
|
|
@@ -604,9 +622,9 @@ export class Matterbridge extends EventEmitter {
|
|
|
604
622
|
plugin.connected = false;
|
|
605
623
|
plugin.registeredDevices = undefined;
|
|
606
624
|
plugin.addedDevices = undefined;
|
|
607
|
-
plugin.qrPairingCode =
|
|
608
|
-
plugin.manualPairingCode =
|
|
609
|
-
this.plugins.load(plugin, true, 'Matterbridge is starting'); //
|
|
625
|
+
plugin.qrPairingCode = undefined;
|
|
626
|
+
plugin.manualPairingCode = undefined;
|
|
627
|
+
this.plugins.load(plugin, true, 'Matterbridge is starting'); // No await do it asyncronously
|
|
610
628
|
}
|
|
611
629
|
await this.startChildbridge();
|
|
612
630
|
return;
|
|
@@ -853,7 +871,10 @@ export class Matterbridge extends EventEmitter {
|
|
|
853
871
|
this.log.debug(`Matterbridge Latest Version: ${this.matterbridgeLatestVersion}`);
|
|
854
872
|
await this.nodeContext?.set('matterbridgeLatestVersion', this.matterbridgeLatestVersion);
|
|
855
873
|
if (this.matterbridgeVersion !== this.matterbridgeLatestVersion) {
|
|
856
|
-
this.log.
|
|
874
|
+
this.log.notice(`Matterbridge is out of date. Current version: ${this.matterbridgeVersion}. Latest version: ${this.matterbridgeLatestVersion}.`);
|
|
875
|
+
}
|
|
876
|
+
else {
|
|
877
|
+
this.log.debug(`Matterbridge is up to date. Current version: ${this.matterbridgeVersion}. Latest version: ${this.matterbridgeLatestVersion}.`);
|
|
857
878
|
}
|
|
858
879
|
})
|
|
859
880
|
.catch((error) => {
|
|
@@ -876,12 +897,12 @@ export class Matterbridge extends EventEmitter {
|
|
|
876
897
|
.then(async (latestVersion) => {
|
|
877
898
|
plugin.latestVersion = latestVersion;
|
|
878
899
|
if (plugin.version !== latestVersion)
|
|
879
|
-
this.log.
|
|
900
|
+
this.log.notice(`The plugin ${plg}${plugin.name}${nt} is out of date. Current version: ${plugin.version}. Latest version: ${latestVersion}.`);
|
|
880
901
|
else
|
|
881
|
-
this.log.
|
|
902
|
+
this.log.debug(`The plugin ${plg}${plugin.name}${db} is up to date. Current version: ${plugin.version}. Latest version: ${latestVersion}.`);
|
|
882
903
|
})
|
|
883
904
|
.catch((error) => {
|
|
884
|
-
this.log.error(`Error getting ${plugin.name} latest version: ${error.message}`);
|
|
905
|
+
this.log.error(`Error getting ${plg}${plugin.name}${er} latest version: ${error.message}`);
|
|
885
906
|
// error.stack && this.log.debug(error.stack);
|
|
886
907
|
});
|
|
887
908
|
}
|
|
@@ -936,12 +957,15 @@ export class Matterbridge extends EventEmitter {
|
|
|
936
957
|
await fs.unlink(filePath);
|
|
937
958
|
}
|
|
938
959
|
catch (error) {
|
|
939
|
-
this.log.debug(`Error unlinking the log file ${CYAN}${filePath}${
|
|
960
|
+
this.log.debug(`Error unlinking the log file ${CYAN}${filePath}${db}: ${error instanceof Error ? error.message : error}`);
|
|
940
961
|
}
|
|
941
962
|
}
|
|
942
963
|
return async (_level, formattedLog) => {
|
|
964
|
+
if (fileSize > 100000000)
|
|
965
|
+
return;
|
|
943
966
|
fileSize += formattedLog.length;
|
|
944
967
|
if (fileSize > 100000000) {
|
|
968
|
+
await fs.appendFile(filePath, `Logging on file has been stoppped because the file size is greater then 100MB.` + os.EOL);
|
|
945
969
|
return;
|
|
946
970
|
}
|
|
947
971
|
const now = new Date();
|
|
@@ -1027,11 +1051,18 @@ export class Matterbridge extends EventEmitter {
|
|
|
1027
1051
|
this.log.info(message);
|
|
1028
1052
|
// Deregisters the SIGINT and SIGTERM signal handlers
|
|
1029
1053
|
this.deregisterSignalHandlers();
|
|
1054
|
+
// Clear the start matter interval
|
|
1055
|
+
if (this.startMatterInterval) {
|
|
1056
|
+
clearInterval(this.startMatterInterval);
|
|
1057
|
+
this.startMatterInterval = undefined;
|
|
1058
|
+
this.log.debug('Start matter interval cleared');
|
|
1059
|
+
}
|
|
1030
1060
|
// Clear the check update interval
|
|
1031
|
-
if (this.checkUpdateInterval)
|
|
1061
|
+
if (this.checkUpdateInterval) {
|
|
1032
1062
|
clearInterval(this.checkUpdateInterval);
|
|
1033
|
-
|
|
1034
|
-
|
|
1063
|
+
this.checkUpdateInterval = undefined;
|
|
1064
|
+
this.log.debug('Check update interval cleared');
|
|
1065
|
+
}
|
|
1035
1066
|
// Clear the configure timeout
|
|
1036
1067
|
if (this.configureTimeout) {
|
|
1037
1068
|
clearTimeout(this.configureTimeout);
|
|
@@ -1265,8 +1296,10 @@ export class Matterbridge extends EventEmitter {
|
|
|
1265
1296
|
this.log.error(`Error removing bridged device ${dev}${device.deviceName}${er} (${dev}${device.name}${er}) for plugin ${plg}${pluginName}${er}: matterAggregator not found`);
|
|
1266
1297
|
return;
|
|
1267
1298
|
}
|
|
1268
|
-
device.
|
|
1269
|
-
|
|
1299
|
+
if (device.number !== undefined) {
|
|
1300
|
+
device.setBridgedDeviceReachability(false);
|
|
1301
|
+
device.getClusterServerById(BridgedDeviceBasicInformation.Cluster.id)?.triggerReachableChangedEvent({ reachableNewValue: false });
|
|
1302
|
+
}
|
|
1270
1303
|
// device.getClusterServerById(BridgedDeviceBasicInformation.Cluster.id)?.triggerShutDownEvent({});
|
|
1271
1304
|
// device.getClusterServerById(BridgedDeviceBasicInformation.Cluster.id)?.triggerLeaveEvent({});
|
|
1272
1305
|
this.matterAggregator?.removeBridgedDevice(device);
|
|
@@ -1307,8 +1340,10 @@ export class Matterbridge extends EventEmitter {
|
|
|
1307
1340
|
return;
|
|
1308
1341
|
}
|
|
1309
1342
|
});
|
|
1310
|
-
device.
|
|
1311
|
-
|
|
1343
|
+
if (device.number !== undefined) {
|
|
1344
|
+
device.setBridgedDeviceReachability(false);
|
|
1345
|
+
device.getClusterServerById(BridgedDeviceBasicInformation.Cluster.id)?.triggerReachableChangedEvent({ reachableNewValue: false });
|
|
1346
|
+
}
|
|
1312
1347
|
plugin.aggregator.removeBridgedDevice(device);
|
|
1313
1348
|
}
|
|
1314
1349
|
this.log.info(`Removed bridged device(${plugin.registeredDevices}/${plugin.addedDevices}) ${dev}${device.deviceName}${nf} (${dev}${device.name}${nf}) for plugin ${plg}${pluginName}${nf}`);
|
|
@@ -1357,13 +1392,14 @@ export class Matterbridge extends EventEmitter {
|
|
|
1357
1392
|
// Plugins are configured by a timer when matter server is started and plugin.configured is set to true
|
|
1358
1393
|
this.log.debug('***Starting startMatterInterval in bridge mode');
|
|
1359
1394
|
let failCount = 0;
|
|
1360
|
-
|
|
1395
|
+
this.startMatterInterval = setInterval(async () => {
|
|
1361
1396
|
for (const plugin of this.plugins) {
|
|
1362
1397
|
// new code to not start the bridge if one plugin is in error cause the controllers will delete the devices loosing all the configuration
|
|
1363
1398
|
if (!plugin.enabled)
|
|
1364
1399
|
continue;
|
|
1365
1400
|
if (plugin.error) {
|
|
1366
|
-
clearInterval(startMatterInterval);
|
|
1401
|
+
clearInterval(this.startMatterInterval);
|
|
1402
|
+
this.startMatterInterval = undefined;
|
|
1367
1403
|
this.log.debug('***Cleared startMatterInterval interval for Matterbridge for plugin in error state');
|
|
1368
1404
|
this.log.error(`The plugin ${plg}${plugin.name}${er} is in error state.`);
|
|
1369
1405
|
this.log.error('The bridge will not start until the problem is solved to prevent the controllers from deleting all registered devices.');
|
|
@@ -1380,7 +1416,8 @@ export class Matterbridge extends EventEmitter {
|
|
|
1380
1416
|
return;
|
|
1381
1417
|
}
|
|
1382
1418
|
}
|
|
1383
|
-
clearInterval(startMatterInterval);
|
|
1419
|
+
clearInterval(this.startMatterInterval);
|
|
1420
|
+
this.startMatterInterval = undefined;
|
|
1384
1421
|
this.log.debug('***Cleared startMatterInterval interval for Matterbridge');
|
|
1385
1422
|
await this.startMatterServer();
|
|
1386
1423
|
this.log.notice('Matter server started');
|
|
@@ -1421,14 +1458,15 @@ export class Matterbridge extends EventEmitter {
|
|
|
1421
1458
|
// Plugins are configured by a timer when matter server is started and plugin.configured is set to true
|
|
1422
1459
|
this.log.debug('***Starting start matter interval in childbridge mode...');
|
|
1423
1460
|
let failCount = 0;
|
|
1424
|
-
|
|
1461
|
+
this.startMatterInterval = setInterval(async () => {
|
|
1425
1462
|
let allStarted = true;
|
|
1426
1463
|
for (const plugin of this.plugins) {
|
|
1427
1464
|
// new code to not start the bridge if one plugin is in error cause the controllers will delete the devices loosing all the configuration
|
|
1428
1465
|
if (!plugin.enabled)
|
|
1429
1466
|
continue;
|
|
1430
1467
|
if (plugin.error) {
|
|
1431
|
-
clearInterval(startMatterInterval);
|
|
1468
|
+
clearInterval(this.startMatterInterval);
|
|
1469
|
+
this.startMatterInterval = undefined;
|
|
1432
1470
|
this.log.debug('***Cleared startMatterInterval interval for Matterbridge for plugin in error state');
|
|
1433
1471
|
this.log.error(`The plugin ${plg}${plugin.name}${er} is in error state.`);
|
|
1434
1472
|
this.log.error('The bridge will not start until the problem is solved to prevent the controllers from deleting all registered devices.');
|
|
@@ -1448,7 +1486,8 @@ export class Matterbridge extends EventEmitter {
|
|
|
1448
1486
|
}
|
|
1449
1487
|
if (!allStarted)
|
|
1450
1488
|
return;
|
|
1451
|
-
clearInterval(startMatterInterval);
|
|
1489
|
+
clearInterval(this.startMatterInterval);
|
|
1490
|
+
this.startMatterInterval = undefined;
|
|
1452
1491
|
this.log.debug('***Cleared startMatterInterval interval in childbridge mode');
|
|
1453
1492
|
await this.startMatterServer();
|
|
1454
1493
|
this.log.notice('Matter server started');
|
|
@@ -1873,8 +1912,8 @@ export class Matterbridge extends EventEmitter {
|
|
|
1873
1912
|
this.log.debug(`Creating matter commissioning server for plugin ${plg}${pluginName}${db} with nodeLabel '${productName}' port ${this.port} passcode ${this.passcode} discriminator ${this.discriminator}`);
|
|
1874
1913
|
const commissioningServer = new CommissioningServer({
|
|
1875
1914
|
port: this.port++,
|
|
1876
|
-
|
|
1877
|
-
|
|
1915
|
+
listeningAddressIpv4: getParameter('ipv4address'),
|
|
1916
|
+
listeningAddressIpv6: getParameter('ipv6address'),
|
|
1878
1917
|
passcode: this.passcode,
|
|
1879
1918
|
discriminator: this.discriminator,
|
|
1880
1919
|
deviceName,
|
|
@@ -2101,16 +2140,15 @@ export class Matterbridge extends EventEmitter {
|
|
|
2101
2140
|
}
|
|
2102
2141
|
if (!commissioningServer.isCommissioned()) {
|
|
2103
2142
|
const { qrPairingCode, manualPairingCode } = commissioningServer.getPairingCode();
|
|
2104
|
-
await storageContext.set('qrPairingCode', qrPairingCode);
|
|
2105
|
-
await storageContext.set('manualPairingCode', manualPairingCode);
|
|
2106
|
-
await nodeContext.set('qrPairingCode', qrPairingCode);
|
|
2107
|
-
await nodeContext.set('manualPairingCode', manualPairingCode);
|
|
2108
2143
|
const QrCode = new QrCodeSchema();
|
|
2109
2144
|
this.log.info(`*The commissioning server on port ${commissioningServer.getPort()} for ${plg}${pluginName}${nf} is not commissioned. Pair it scanning the QR code:\n\n`);
|
|
2110
2145
|
// eslint-disable-next-line no-console
|
|
2111
|
-
|
|
2112
|
-
|
|
2146
|
+
if (this.log.logLevel === "debug" /* LogLevel.DEBUG */ || this.log.logLevel === "info" /* LogLevel.INFO */)
|
|
2147
|
+
console.log(`${QrCode.encode(qrPairingCode)}\n`);
|
|
2148
|
+
this.log.info(`${plg}${pluginName}${nf} \n\nqrPairingCode: ${qrPairingCode} \n\nManual pairing code: ${manualPairingCode}\n`);
|
|
2113
2149
|
if (pluginName === 'Matterbridge') {
|
|
2150
|
+
this.matterbridgeQrPairingCode = qrPairingCode;
|
|
2151
|
+
this.matterbridgeManualPairingCode = manualPairingCode;
|
|
2114
2152
|
this.matterbridgeFabricInformations = [];
|
|
2115
2153
|
this.matterbridgeSessionInformations = [];
|
|
2116
2154
|
this.matterbridgePaired = false;
|
|
@@ -2595,40 +2633,21 @@ export class Matterbridge extends EventEmitter {
|
|
|
2595
2633
|
// Endpoint to provide settings
|
|
2596
2634
|
this.expressApp.get('/api/settings', express.json(), async (req, res) => {
|
|
2597
2635
|
this.log.debug('The frontend sent /api/settings');
|
|
2598
|
-
if (!this.matterbridgeContext) {
|
|
2599
|
-
this.log.error('/api/settings matterbridgeContext not found');
|
|
2600
|
-
res.json({});
|
|
2601
|
-
return;
|
|
2602
|
-
}
|
|
2603
|
-
let qrPairingCode = '';
|
|
2604
|
-
let manualPairingCode = '';
|
|
2605
|
-
try {
|
|
2606
|
-
qrPairingCode = await this.matterbridgeContext.get('qrPairingCode');
|
|
2607
|
-
manualPairingCode = await this.matterbridgeContext.get('manualPairingCode');
|
|
2608
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
2609
|
-
}
|
|
2610
|
-
catch (error) {
|
|
2611
|
-
if (this.bridgeMode === 'bridge')
|
|
2612
|
-
this.log.warn('pairingCodes for /api/settings not found');
|
|
2613
|
-
}
|
|
2614
2636
|
this.matterbridgeInformation.bridgeMode = this.bridgeMode;
|
|
2615
2637
|
this.matterbridgeInformation.restartMode = this.restartMode;
|
|
2616
2638
|
this.matterbridgeInformation.loggerLevel = this.log.logLevel;
|
|
2617
2639
|
this.matterbridgeInformation.matterLoggerLevel = Logger.defaultLogLevel;
|
|
2618
2640
|
this.matterbridgeInformation.matterbridgePaired = this.matterbridgePaired;
|
|
2619
2641
|
this.matterbridgeInformation.matterbridgeConnected = this.matterbridgeConnected;
|
|
2642
|
+
this.matterbridgeInformation.matterbridgeQrPairingCode = this.matterbridgeQrPairingCode;
|
|
2643
|
+
this.matterbridgeInformation.matterbridgeManualPairingCode = this.matterbridgeManualPairingCode;
|
|
2620
2644
|
this.matterbridgeInformation.matterbridgeFabricInformations = this.matterbridgeFabricInformations;
|
|
2621
2645
|
this.matterbridgeInformation.matterbridgeSessionInformations = this.matterbridgeSessionInformations;
|
|
2622
2646
|
if (this.profile)
|
|
2623
2647
|
this.matterbridgeInformation.profile = this.profile;
|
|
2624
|
-
const response = { wssHost, ssl: hasParameter('ssl'), qrPairingCode, manualPairingCode, systemInformation: this.systemInformation, matterbridgeInformation: this.matterbridgeInformation };
|
|
2648
|
+
// const response = { wssHost, ssl: hasParameter('ssl'), qrPairingCode, manualPairingCode, systemInformation: this.systemInformation, matterbridgeInformation: this.matterbridgeInformation };
|
|
2649
|
+
const response = { wssHost, ssl: hasParameter('ssl'), systemInformation: this.systemInformation, matterbridgeInformation: this.matterbridgeInformation };
|
|
2625
2650
|
// this.log.debug('Response:', debugStringify(response));
|
|
2626
|
-
/*
|
|
2627
|
-
if (this.webSocketServer && this.webSocketServer.clients.size > 0 && !AnsiLogger.getGlobalCallback()) {
|
|
2628
|
-
AnsiLogger.setGlobalCallback(this.wssSendMessage.bind(this), LogLevel.DEBUG);
|
|
2629
|
-
this.log.debug('WebSocketServer logger global callback added');
|
|
2630
|
-
}
|
|
2631
|
-
*/
|
|
2632
2651
|
res.json(response);
|
|
2633
2652
|
});
|
|
2634
2653
|
// Endpoint to provide plugins
|
|
@@ -2801,8 +2820,8 @@ export class Matterbridge extends EventEmitter {
|
|
|
2801
2820
|
// Endpoint to download the matterbridge storage directory
|
|
2802
2821
|
this.expressApp.get('/api/download-mbstorage', async (req, res) => {
|
|
2803
2822
|
this.log.debug('The frontend sent /api/download-mbstorage');
|
|
2804
|
-
await
|
|
2805
|
-
res.download(path.join(
|
|
2823
|
+
await createZip(path.join(os.tmpdir(), `matterbridge.${this.nodeStorageName}.zip`), path.join(this.matterbridgeDirectory, this.nodeStorageName));
|
|
2824
|
+
res.download(path.join(os.tmpdir(), `matterbridge.${this.nodeStorageName}.zip`), `matterbridge.${this.nodeStorageName}.zip`, (error) => {
|
|
2806
2825
|
if (error) {
|
|
2807
2826
|
this.log.error(`Error downloading file ${`matterbridge.${this.nodeStorageName}.zip`}: ${error instanceof Error ? error.message : error}`);
|
|
2808
2827
|
res.status(500).send('Error downloading the matterbridge storage file');
|
|
@@ -2812,14 +2831,36 @@ export class Matterbridge extends EventEmitter {
|
|
|
2812
2831
|
// Endpoint to download the matterbridge plugin directory
|
|
2813
2832
|
this.expressApp.get('/api/download-pluginstorage', async (req, res) => {
|
|
2814
2833
|
this.log.debug('The frontend sent /api/download-pluginstorage');
|
|
2815
|
-
await
|
|
2816
|
-
res.download(path.join(
|
|
2834
|
+
await createZip(path.join(os.tmpdir(), `matterbridge.pluginstorage.zip`), this.matterbridgePluginDirectory);
|
|
2835
|
+
res.download(path.join(os.tmpdir(), `matterbridge.pluginstorage.zip`), `matterbridge.pluginstorage.zip`, (error) => {
|
|
2817
2836
|
if (error) {
|
|
2818
2837
|
this.log.error(`Error downloading file matterbridge.pluginstorage.zip: ${error instanceof Error ? error.message : error}`);
|
|
2819
2838
|
res.status(500).send('Error downloading the matterbridge plugin storage file');
|
|
2820
2839
|
}
|
|
2821
2840
|
});
|
|
2822
2841
|
});
|
|
2842
|
+
// Endpoint to download the matterbridge plugin config files
|
|
2843
|
+
this.expressApp.get('/api/download-pluginconfig', async (req, res) => {
|
|
2844
|
+
this.log.debug('The frontend sent /api/download-pluginconfig');
|
|
2845
|
+
await createZip(path.join(os.tmpdir(), `matterbridge.pluginconfig.zip`), path.relative(process.cwd(), path.join(this.matterbridgeDirectory, '*.config.json')));
|
|
2846
|
+
// await createZip(path.join(os.tmpdir(), `matterbridge.pluginconfig.zip`), path.relative(process.cwd(), path.join(this.matterbridgeDirectory, 'certs', '*.*')), path.relative(process.cwd(), path.join(this.matterbridgeDirectory, '*.config.json')));
|
|
2847
|
+
res.download(path.join(os.tmpdir(), `matterbridge.pluginconfig.zip`), `matterbridge.pluginconfig.zip`, (error) => {
|
|
2848
|
+
if (error) {
|
|
2849
|
+
this.log.error(`Error downloading file matterbridge.pluginstorage.zip: ${error instanceof Error ? error.message : error}`);
|
|
2850
|
+
res.status(500).send('Error downloading the matterbridge plugin storage file');
|
|
2851
|
+
}
|
|
2852
|
+
});
|
|
2853
|
+
});
|
|
2854
|
+
// Endpoint to download the matterbridge plugin config files
|
|
2855
|
+
this.expressApp.get('/api/download-backup', async (req, res) => {
|
|
2856
|
+
this.log.debug('The frontend sent /api/download-backup');
|
|
2857
|
+
res.download(path.join(os.tmpdir(), `matterbridge.backup.zip`), `matterbridge.backup.zip`, (error) => {
|
|
2858
|
+
if (error) {
|
|
2859
|
+
this.log.error(`Error downloading file matterbridge.backup.zip: ${error instanceof Error ? error.message : error}`);
|
|
2860
|
+
res.status(500).send(`Error downloading file matterbridge.backup.zip: ${error instanceof Error ? error.message : error}`);
|
|
2861
|
+
}
|
|
2862
|
+
});
|
|
2863
|
+
});
|
|
2823
2864
|
// Endpoint to receive commands
|
|
2824
2865
|
this.expressApp.post('/api/command/:command/:param', express.json(), async (req, res) => {
|
|
2825
2866
|
const command = req.params.command;
|
|
@@ -2838,6 +2879,21 @@ export class Matterbridge extends EventEmitter {
|
|
|
2838
2879
|
res.json({ message: 'Command received' });
|
|
2839
2880
|
return;
|
|
2840
2881
|
}
|
|
2882
|
+
// Handle the command setbridgemode from Settings
|
|
2883
|
+
if (command === 'setbridgemode') {
|
|
2884
|
+
this.log.debug(`setbridgemode: ${param}`);
|
|
2885
|
+
await this.nodeContext?.set('bridgeMode', param);
|
|
2886
|
+
res.json({ message: 'Command received' });
|
|
2887
|
+
return;
|
|
2888
|
+
}
|
|
2889
|
+
// Handle the command backup from Settings
|
|
2890
|
+
if (command === 'backup') {
|
|
2891
|
+
this.log.notice(`Prepairing the backup...`);
|
|
2892
|
+
await createZip(path.join(os.tmpdir(), `matterbridge.backup.zip`), path.join(this.matterbridgeDirectory), path.join(this.matterbridgePluginDirectory));
|
|
2893
|
+
this.log.notice(`Backup ready to be downloaded.`);
|
|
2894
|
+
res.json({ message: 'Command received' });
|
|
2895
|
+
return;
|
|
2896
|
+
}
|
|
2841
2897
|
// Handle the command setmbloglevel from Settings
|
|
2842
2898
|
if (command === 'setmbloglevel') {
|
|
2843
2899
|
this.log.debug('Matterbridge log level:', param);
|
|
@@ -2915,13 +2971,6 @@ export class Matterbridge extends EventEmitter {
|
|
|
2915
2971
|
this.matterbridgeInformation.matterFileLogger = param === 'true';
|
|
2916
2972
|
await this.nodeContext?.set('matterFileLog', param === 'true');
|
|
2917
2973
|
if (param === 'true') {
|
|
2918
|
-
/*
|
|
2919
|
-
try {
|
|
2920
|
-
await fs.unlink(path.join(this.matterbridgeDirectory, this.matterLoggerFile));
|
|
2921
|
-
} catch (error) {
|
|
2922
|
-
this.log.debug(`Error unlinking the log file ${CYAN}${path.join(this.matterbridgeDirectory, this.matterLoggerFile)}${er}: ${error instanceof Error ? error.message : error}`);
|
|
2923
|
-
}
|
|
2924
|
-
*/
|
|
2925
2974
|
try {
|
|
2926
2975
|
Logger.addLogger('matterfilelogger', await this.createMatterFileLogger(path.join(this.matterbridgeDirectory, this.matterLoggerFile), true), {
|
|
2927
2976
|
defaultLogLevel: Level.DEBUG,
|