matterbridge 1.4.0 → 1.4.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/CHANGELOG.md +38 -1
- package/README.md +6 -4
- package/dist/cluster/AirQualityCluster.d.ts.map +1 -1
- package/dist/cluster/AirQualityCluster.js +1 -0
- package/dist/cluster/AirQualityCluster.js.map +1 -1
- package/dist/cluster/BridgedDeviceBasicInformationCluster.d.ts.map +1 -1
- package/dist/cluster/BridgedDeviceBasicInformationCluster.js +1 -0
- package/dist/cluster/BridgedDeviceBasicInformationCluster.js.map +1 -1
- package/dist/cluster/PowerTopologyCluster.d.ts.map +1 -1
- package/dist/cluster/PowerTopologyCluster.js +1 -1
- package/dist/cluster/PowerTopologyCluster.js.map +1 -1
- package/dist/cluster/TvocCluster.d.ts.map +1 -1
- package/dist/cluster/TvocCluster.js +1 -0
- package/dist/cluster/TvocCluster.js.map +1 -1
- package/dist/deviceManager.d.ts +46 -0
- package/dist/deviceManager.d.ts.map +1 -0
- package/dist/deviceManager.js +92 -0
- package/dist/deviceManager.js.map +1 -0
- package/dist/matterbridge.d.ts +21 -76
- package/dist/matterbridge.d.ts.map +1 -1
- package/dist/matterbridge.js +345 -459
- package/dist/matterbridge.js.map +1 -1
- package/dist/matterbridgeDevice.d.ts +69 -148
- package/dist/matterbridgeDevice.d.ts.map +1 -1
- package/dist/matterbridgeDevice.js +232 -30
- package/dist/matterbridgeDevice.js.map +1 -1
- package/dist/matterbridgePlatform.d.ts +6 -1
- package/dist/matterbridgePlatform.d.ts.map +1 -1
- package/dist/matterbridgePlatform.js +8 -0
- package/dist/matterbridgePlatform.js.map +1 -1
- package/dist/matterbridgeTypes.d.ts +28 -1
- package/dist/matterbridgeTypes.d.ts.map +1 -1
- package/dist/matterbridgeTypes.js +26 -1
- package/dist/matterbridgeTypes.js.map +1 -1
- package/dist/{plugins.d.ts → pluginManager.d.ts} +6 -3
- package/dist/pluginManager.d.ts.map +1 -0
- package/dist/{plugins.js → pluginManager.js} +26 -16
- package/dist/pluginManager.js.map +1 -0
- package/dist/utils/utils.d.ts +57 -0
- package/dist/utils/utils.d.ts.map +1 -1
- package/dist/utils/utils.js +103 -0
- package/dist/utils/utils.js.map +1 -1
- package/frontend/build/asset-manifest.json +6 -6
- package/frontend/build/index.html +1 -1
- package/frontend/build/static/css/{main.df840158.css → main.5174e68c.css} +2 -2
- package/frontend/build/static/css/{main.df840158.css.map → main.5174e68c.css.map} +1 -1
- package/frontend/build/static/js/{main.2a46688a.js → main.dec34964.js} +3 -3
- package/frontend/build/static/js/main.dec34964.js.map +1 -0
- package/package.json +26 -25
- package/dist/plugins.d.ts.map +0 -1
- package/dist/plugins.js.map +0 -1
- package/frontend/build/static/js/main.2a46688a.js.map +0 -1
- /package/frontend/build/static/js/{main.2a46688a.js.LICENSE.txt → main.dec34964.js.LICENSE.txt} +0 -0
package/dist/matterbridge.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* @file matterbridge.ts
|
|
5
5
|
* @author Luca Liguori
|
|
6
6
|
* @date 2023-12-29
|
|
7
|
-
* @version 1.
|
|
7
|
+
* @version 1.4.0
|
|
8
8
|
*
|
|
9
9
|
* Copyright 2023, 2024 Luca Liguori.
|
|
10
10
|
*
|
|
@@ -21,8 +21,8 @@
|
|
|
21
21
|
* limitations under the License. *
|
|
22
22
|
*/
|
|
23
23
|
import { NodeStorageManager } from 'node-persist-manager';
|
|
24
|
-
import { AnsiLogger,
|
|
25
|
-
import { fileURLToPath
|
|
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';
|
|
25
|
+
import { fileURLToPath } from 'url';
|
|
26
26
|
import { promises as fs } from 'fs';
|
|
27
27
|
import { exec, spawn } from 'child_process';
|
|
28
28
|
import { createServer } from 'http';
|
|
@@ -34,7 +34,6 @@ import path from 'path';
|
|
|
34
34
|
import WebSocket, { WebSocketServer } from 'ws';
|
|
35
35
|
// Matterbridge
|
|
36
36
|
import { MatterbridgeDevice } from './matterbridgeDevice.js';
|
|
37
|
-
import { shelly_config, somfytahoma_config, zigbee2mqtt_config } from './defaultConfigSchema.js';
|
|
38
37
|
import { BridgedDeviceBasicInformation, BridgedDeviceBasicInformationCluster } from './cluster/BridgedDeviceBasicInformationCluster.js';
|
|
39
38
|
import { logInterfaces, wait, waiter } from './utils/utils.js';
|
|
40
39
|
// @project-chip/matter-node.js
|
|
@@ -42,12 +41,13 @@ import { CommissioningController, CommissioningServer, MatterServer } from '@pro
|
|
|
42
41
|
import { BasicInformationCluster, ClusterServer, FixedLabelCluster, GeneralCommissioning, PowerSourceCluster, SwitchCluster, ThreadNetworkDiagnosticsCluster, getClusterNameById } from '@project-chip/matter-node.js/cluster';
|
|
43
42
|
import { DeviceTypeId, VendorId } from '@project-chip/matter-node.js/datatype';
|
|
44
43
|
import { Aggregator, DeviceTypes, NodeStateInformation } from '@project-chip/matter-node.js/device';
|
|
45
|
-
import { Format, Level, Logger } from '@project-chip/matter-node.js/log';
|
|
44
|
+
import { createFileLogger, Format, Level, Logger } from '@project-chip/matter-node.js/log';
|
|
46
45
|
import { ManualPairingCodeCodec, QrCodeSchema } from '@project-chip/matter-node.js/schema';
|
|
47
46
|
import { StorageBackendDisk, StorageBackendJsonFile, StorageManager } from '@project-chip/matter-node.js/storage';
|
|
48
47
|
import { requireMinNodeVersion, getParameter, getIntParameter, hasParameter } from '@project-chip/matter-node.js/util';
|
|
49
48
|
import { CryptoNode } from '@project-chip/matter-node.js/crypto';
|
|
50
|
-
import {
|
|
49
|
+
import { PluginManager } from './pluginManager.js';
|
|
50
|
+
import { DeviceManager } from './deviceManager.js';
|
|
51
51
|
// Default colors
|
|
52
52
|
const plg = '\u001B[38;5;33m';
|
|
53
53
|
const dev = '\u001B[38;5;79m';
|
|
@@ -86,7 +86,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
86
86
|
matterbridgeConnected: false,
|
|
87
87
|
bridgeMode: '',
|
|
88
88
|
restartMode: '',
|
|
89
|
-
|
|
89
|
+
loggerLevel: "info" /* LogLevel.INFO */,
|
|
90
90
|
matterLoggerLevel: Level.INFO,
|
|
91
91
|
};
|
|
92
92
|
homeDirectory = '';
|
|
@@ -102,10 +102,14 @@ export class Matterbridge extends EventEmitter {
|
|
|
102
102
|
matterbridgeConnected = false;
|
|
103
103
|
bridgeMode = '';
|
|
104
104
|
restartMode = '';
|
|
105
|
-
debugEnabled = false;
|
|
105
|
+
// public debugEnabled = false;
|
|
106
|
+
// public loggerLevel: LogLevel = LogLevel.INFO;
|
|
106
107
|
profile = getParameter('profile');
|
|
107
108
|
log;
|
|
109
|
+
matterbrideLoggerFile = 'matterbridge' + (getParameter('profile') ? '.' + getParameter('profile') : '') + '.log';
|
|
110
|
+
matterLoggerFile = 'matter' + (getParameter('profile') ? '.' + getParameter('profile') : '') + '.log';
|
|
108
111
|
plugins;
|
|
112
|
+
devices;
|
|
109
113
|
registeredDevices = [];
|
|
110
114
|
nodeStorage;
|
|
111
115
|
nodeContext;
|
|
@@ -201,12 +205,46 @@ export class Matterbridge extends EventEmitter {
|
|
|
201
205
|
this.restartMode = 'service';
|
|
202
206
|
if (hasParameter('docker'))
|
|
203
207
|
this.restartMode = 'docker';
|
|
204
|
-
// Set
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
+
// Set the matterbridge directory
|
|
209
|
+
this.homeDirectory = os.homedir();
|
|
210
|
+
this.matterbridgeDirectory = path.join(this.homeDirectory, '.matterbridge');
|
|
211
|
+
// Create the file logger for matterbridge
|
|
212
|
+
if (hasParameter('filelogger'))
|
|
213
|
+
AnsiLogger.setGlobalLogfile(path.join(this.matterbridgeDirectory, this.matterbrideLoggerFile), "debug" /* LogLevel.DEBUG */, true);
|
|
214
|
+
// Create matterbridge logger
|
|
215
|
+
this.log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: "info" /* LogLevel.INFO */ });
|
|
216
|
+
// Set matterbridge logger level
|
|
217
|
+
if (hasParameter('logger')) {
|
|
218
|
+
const level = getParameter('logger');
|
|
219
|
+
if (level === 'debug') {
|
|
220
|
+
this.log.logLevel = "debug" /* LogLevel.DEBUG */;
|
|
221
|
+
}
|
|
222
|
+
else if (level === 'info') {
|
|
223
|
+
this.log.logLevel = "info" /* LogLevel.INFO */;
|
|
224
|
+
}
|
|
225
|
+
else if (level === 'notice') {
|
|
226
|
+
this.log.logLevel = "notice" /* LogLevel.NOTICE */;
|
|
227
|
+
}
|
|
228
|
+
else if (level === 'warn') {
|
|
229
|
+
this.log.logLevel = "warn" /* LogLevel.WARN */;
|
|
230
|
+
}
|
|
231
|
+
else if (level === 'error') {
|
|
232
|
+
this.log.logLevel = "error" /* LogLevel.ERROR */;
|
|
233
|
+
}
|
|
234
|
+
else if (level === 'fatal') {
|
|
235
|
+
this.log.logLevel = "fatal" /* LogLevel.FATAL */;
|
|
236
|
+
}
|
|
237
|
+
else {
|
|
238
|
+
this.log.warn(`Invalid matterbridge logger level: ${level}. Using default level "info".`);
|
|
239
|
+
this.log.logLevel = "info" /* LogLevel.INFO */;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
else {
|
|
243
|
+
this.log.logLevel = "info" /* LogLevel.INFO */;
|
|
244
|
+
}
|
|
245
|
+
MatterbridgeDevice.logLevel = this.log.logLevel;
|
|
208
246
|
this.log.debug('Matterbridge is starting...');
|
|
209
|
-
// Set matter.js logger level and
|
|
247
|
+
// Set matter.js logger level, format and logger
|
|
210
248
|
if (hasParameter('matterlogger')) {
|
|
211
249
|
const level = getParameter('matterlogger');
|
|
212
250
|
if (level === 'debug') {
|
|
@@ -228,7 +266,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
228
266
|
Logger.defaultLogLevel = Level.FATAL;
|
|
229
267
|
}
|
|
230
268
|
else {
|
|
231
|
-
this.log.warn(`Invalid
|
|
269
|
+
this.log.warn(`Invalid matter.js logger level: ${level}. Using default level "info".`);
|
|
232
270
|
Logger.defaultLogLevel = Level.INFO;
|
|
233
271
|
}
|
|
234
272
|
}
|
|
@@ -236,16 +274,30 @@ export class Matterbridge extends EventEmitter {
|
|
|
236
274
|
Logger.defaultLogLevel = Level.INFO;
|
|
237
275
|
}
|
|
238
276
|
Logger.format = Format.ANSI;
|
|
277
|
+
Logger.setLogger('default', this.createMatterLogger());
|
|
278
|
+
// Create the file logger for matter.js
|
|
279
|
+
if (hasParameter('matterfilelogger')) {
|
|
280
|
+
try {
|
|
281
|
+
await fs.unlink(path.join(this.matterbridgeDirectory, this.matterLoggerFile));
|
|
282
|
+
}
|
|
283
|
+
catch (error) {
|
|
284
|
+
this.log.debug(`Error unlinking the log file ${CYAN}${path.join(this.matterbridgeDirectory, this.matterLoggerFile)}${er}: ${error instanceof Error ? error.message : error}`);
|
|
285
|
+
}
|
|
286
|
+
Logger.addLogger('filelogger', await createFileLogger(path.join(this.matterbridgeDirectory, this.matterLoggerFile)), {
|
|
287
|
+
defaultLogLevel: Level.DEBUG,
|
|
288
|
+
logFormat: Format.PLAIN,
|
|
289
|
+
});
|
|
290
|
+
}
|
|
239
291
|
// Initialize nodeStorage and nodeContext
|
|
240
|
-
this.homeDirectory = os.homedir();
|
|
241
|
-
this.matterbridgeDirectory = path.join(this.homeDirectory, '.matterbridge');
|
|
242
292
|
this.log.debug(`Creating node storage manager: ${CYAN}${this.nodeStorageName}${db}`);
|
|
243
293
|
this.nodeStorage = new NodeStorageManager({ dir: path.join(this.matterbridgeDirectory, this.nodeStorageName), writeQueue: false, expiredInterval: undefined, logging: false });
|
|
244
294
|
this.log.debug('Creating node storage context for matterbridge');
|
|
245
295
|
this.nodeContext = await this.nodeStorage.createStorage('matterbridge');
|
|
246
|
-
// Initialize
|
|
247
|
-
this.plugins = new
|
|
296
|
+
// Initialize PluginManager
|
|
297
|
+
this.plugins = new PluginManager(this);
|
|
248
298
|
await this.plugins.loadFromStorage();
|
|
299
|
+
// Initialize DeviceManager
|
|
300
|
+
this.devices = new DeviceManager(this, this.nodeContext);
|
|
249
301
|
// Get the plugins from node storage and create the plugins node storage contexts
|
|
250
302
|
for (const plugin of this.plugins) {
|
|
251
303
|
const packageJson = await this.plugins.parse(plugin);
|
|
@@ -256,6 +308,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
256
308
|
await this.spawnCommand('npm', ['install', '-g', plugin.name]);
|
|
257
309
|
this.log.info(`Plugin ${plg}${plugin.name}${nf} reinstalled.`);
|
|
258
310
|
plugin.error = false;
|
|
311
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
259
312
|
}
|
|
260
313
|
catch (error) {
|
|
261
314
|
plugin.error = true;
|
|
@@ -274,7 +327,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
274
327
|
}
|
|
275
328
|
// Log system info and create .matterbridge directory
|
|
276
329
|
await this.logNodeAndSystemInfo();
|
|
277
|
-
this.log.
|
|
330
|
+
this.log.notice(`Matterbridge version ${this.matterbridgeVersion} ${hasParameter('bridge') ? 'mode bridge' : ''}${hasParameter('childbridge') ? 'mode childbridge' : ''}${hasParameter('controller') ? 'mode controller' : ''} ` +
|
|
278
331
|
`${this.restartMode !== '' ? 'restart mode ' + this.restartMode + ' ' : ''}running on ${this.systemInformation.osType} ${this.systemInformation.osRelease} ${this.systemInformation.osPlatform} ${this.systemInformation.osArch} `);
|
|
279
332
|
// Check node version and throw error
|
|
280
333
|
requireMinNodeVersion(18);
|
|
@@ -299,7 +352,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
299
352
|
- port [port]: start the commissioning server on the given port (default 5540)
|
|
300
353
|
- mdnsinterface [name]: set the interface to use for the matter server mdnsInterface (default all interfaces)
|
|
301
354
|
- frontend [port]: start the frontend on the given port (default 8283)
|
|
302
|
-
-
|
|
355
|
+
- logger: set the matterbridge logger level: debug | info | notice | warn | error | fatal (default info)
|
|
303
356
|
- matterlogger: set the matter.js logger level: debug | info | notice | warn | error | fatal (default info)
|
|
304
357
|
- reset: remove the commissioning for Matterbridge (bridge mode). Shutdown Matterbridge before using it!
|
|
305
358
|
- factoryreset: remove all commissioning information and reset all internal storages. Shutdown Matterbridge before using it!
|
|
@@ -417,13 +470,13 @@ export class Matterbridge extends EventEmitter {
|
|
|
417
470
|
return;
|
|
418
471
|
}
|
|
419
472
|
// Start the matter storage and create the matterbridge context
|
|
420
|
-
await this.
|
|
473
|
+
await this.startMatterStorage('json', path.join(this.matterbridgeDirectory, this.matterStorageName));
|
|
421
474
|
this.log.debug(`Creating commissioning server context for ${plg}Matterbridge${db}`);
|
|
422
475
|
this.matterbridgeContext = await this.createCommissioningServerContext('Matterbridge', 'Matterbridge', DeviceTypes.AGGREGATOR.code, 0xfff1, 'Matterbridge', 0x8000, 'Matterbridge aggregator');
|
|
423
476
|
if (hasParameter('reset') && getParameter('reset') === undefined) {
|
|
424
477
|
this.log.info('Resetting Matterbridge commissioning information...');
|
|
425
478
|
await this.matterbridgeContext?.clearAll();
|
|
426
|
-
await this.
|
|
479
|
+
await this.stopMatterStorage();
|
|
427
480
|
this.log.info('Reset done! Remove the device from the controller.');
|
|
428
481
|
this.emit('shutdown');
|
|
429
482
|
return;
|
|
@@ -443,7 +496,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
443
496
|
else {
|
|
444
497
|
this.log.warn(`Plugin ${plg}${getParameter('reset')}${wr} not registerd in matterbridge`);
|
|
445
498
|
}
|
|
446
|
-
await this.
|
|
499
|
+
await this.stopMatterStorage();
|
|
447
500
|
this.emit('shutdown');
|
|
448
501
|
return;
|
|
449
502
|
}
|
|
@@ -484,8 +537,8 @@ export class Matterbridge extends EventEmitter {
|
|
|
484
537
|
this.log.debug('Adding matterbridge commissioning server to matter server');
|
|
485
538
|
await this.matterServer.addCommissioningServer(this.commissioningServer, { uniqueStorageKey: 'Matterbridge' });
|
|
486
539
|
for (const plugin of this.plugins) {
|
|
487
|
-
plugin.configJson = await this.
|
|
488
|
-
plugin.schemaJson = await this.
|
|
540
|
+
plugin.configJson = await this.plugins.loadConfig(plugin);
|
|
541
|
+
plugin.schemaJson = await this.plugins.loadSchema(plugin);
|
|
489
542
|
// Check if the plugin is available
|
|
490
543
|
if (!(await this.plugins.resolve(plugin.path))) {
|
|
491
544
|
this.log.error(`Plugin ${plg}${plugin.name}${er} not found. Disabling it.`);
|
|
@@ -509,7 +562,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
509
562
|
plugin.addedDevices = undefined;
|
|
510
563
|
plugin.qrPairingCode = undefined;
|
|
511
564
|
plugin.manualPairingCode = undefined;
|
|
512
|
-
this.loadPlugin(plugin, true, 'Matterbridge is starting'); // No await do it asyncronously
|
|
565
|
+
this.plugins.load(plugin, true, 'Matterbridge is starting'); // this.loadPlugin(plugin, true, 'Matterbridge is starting'); // No await do it asyncronously
|
|
513
566
|
}
|
|
514
567
|
await this.startBridge();
|
|
515
568
|
return;
|
|
@@ -522,8 +575,8 @@ export class Matterbridge extends EventEmitter {
|
|
|
522
575
|
this.log.debug('Starting matterbridge in mode', this.bridgeMode);
|
|
523
576
|
this.matterServer = this.createMatterServer(this.storageManager);
|
|
524
577
|
for (const plugin of this.plugins) {
|
|
525
|
-
plugin.configJson = await this.
|
|
526
|
-
plugin.schemaJson = await this.
|
|
578
|
+
plugin.configJson = await this.plugins.loadConfig(plugin);
|
|
579
|
+
plugin.schemaJson = await this.plugins.loadSchema(plugin);
|
|
527
580
|
// Check if the plugin is available
|
|
528
581
|
if (!(await this.plugins.resolve(plugin.path))) {
|
|
529
582
|
this.log.error(`Plugin ${plg}${plugin.name}${er} not found. Disabling it.`);
|
|
@@ -547,7 +600,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
547
600
|
plugin.addedDevices = undefined;
|
|
548
601
|
plugin.qrPairingCode = (await plugin.nodeContext?.get('qrPairingCode', undefined)) ?? undefined;
|
|
549
602
|
plugin.manualPairingCode = (await plugin.nodeContext?.get('manualPairingCode', undefined)) ?? undefined;
|
|
550
|
-
this.loadPlugin(plugin, true, 'Matterbridge is starting'); // No await do it asyncronously
|
|
603
|
+
this.plugins.load(plugin, true, 'Matterbridge is starting'); // this.loadPlugin(plugin, true, 'Matterbridge is starting'); // No await do it asyncronously
|
|
551
604
|
}
|
|
552
605
|
await this.startChildbridge();
|
|
553
606
|
return;
|
|
@@ -573,9 +626,11 @@ export class Matterbridge extends EventEmitter {
|
|
|
573
626
|
*/
|
|
574
627
|
deregisterSignalHandlers() {
|
|
575
628
|
this.log.debug(`Deregistering SIGINT and SIGTERM signal handlers...`);
|
|
576
|
-
|
|
629
|
+
if (this.sigintHandler)
|
|
630
|
+
process.off('SIGINT', this.sigintHandler);
|
|
577
631
|
this.sigintHandler = undefined;
|
|
578
|
-
|
|
632
|
+
if (this.sigtermHandler)
|
|
633
|
+
process.off('SIGTERM', this.sigtermHandler);
|
|
579
634
|
this.sigtermHandler = undefined;
|
|
580
635
|
}
|
|
581
636
|
/**
|
|
@@ -824,6 +879,37 @@ export class Matterbridge extends EventEmitter {
|
|
|
824
879
|
// error.stack && this.log.debug(error.stack);
|
|
825
880
|
});
|
|
826
881
|
}
|
|
882
|
+
createMatterLogger() {
|
|
883
|
+
const matterLogger = new AnsiLogger({ logName: 'Matter', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: "debug" /* LogLevel.DEBUG */ });
|
|
884
|
+
return (_level, formattedLog) => {
|
|
885
|
+
const logger = formattedLog.slice(44, 44 + 20).trim();
|
|
886
|
+
const message = formattedLog.slice(65);
|
|
887
|
+
matterLogger.logName = logger;
|
|
888
|
+
switch (_level) {
|
|
889
|
+
case Level.DEBUG:
|
|
890
|
+
matterLogger.log("debug" /* LogLevel.DEBUG */, message);
|
|
891
|
+
break;
|
|
892
|
+
case Level.INFO:
|
|
893
|
+
matterLogger.log("info" /* LogLevel.INFO */, message);
|
|
894
|
+
break;
|
|
895
|
+
case Level.NOTICE:
|
|
896
|
+
matterLogger.log("notice" /* LogLevel.NOTICE */, message);
|
|
897
|
+
break;
|
|
898
|
+
case Level.WARN:
|
|
899
|
+
matterLogger.log("warn" /* LogLevel.WARN */, message);
|
|
900
|
+
break;
|
|
901
|
+
case Level.ERROR:
|
|
902
|
+
matterLogger.log("error" /* LogLevel.ERROR */, message);
|
|
903
|
+
break;
|
|
904
|
+
case Level.FATAL:
|
|
905
|
+
matterLogger.log("fatal" /* LogLevel.FATAL */, message);
|
|
906
|
+
break;
|
|
907
|
+
default:
|
|
908
|
+
matterLogger.log("debug" /* LogLevel.DEBUG */, message);
|
|
909
|
+
break;
|
|
910
|
+
}
|
|
911
|
+
};
|
|
912
|
+
}
|
|
827
913
|
/**
|
|
828
914
|
* Update matterbridge and cleanup.
|
|
829
915
|
*/
|
|
@@ -945,8 +1031,8 @@ export class Matterbridge extends EventEmitter {
|
|
|
945
1031
|
// this.cleanupTimeout1 = setTimeout(async () => {
|
|
946
1032
|
// Closing matter
|
|
947
1033
|
await this.stopMatterServer();
|
|
948
|
-
// Closing storage
|
|
949
|
-
await this.
|
|
1034
|
+
// Closing matter storage
|
|
1035
|
+
await this.stopMatterStorage();
|
|
950
1036
|
// Serialize registeredDevices
|
|
951
1037
|
if (this.nodeStorage && this.nodeContext) {
|
|
952
1038
|
this.log.info('Saving registered devices...');
|
|
@@ -1010,7 +1096,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
1010
1096
|
await fs.rm(path.join(this.matterbridgeDirectory, this.nodeStorageName), { recursive: true });
|
|
1011
1097
|
this.log.info('Factory reset done! Remove all paired devices from the controllers.');
|
|
1012
1098
|
}
|
|
1013
|
-
this.log.
|
|
1099
|
+
this.log.notice('Cleanup completed. Shutting down...');
|
|
1014
1100
|
Matterbridge.instance = undefined;
|
|
1015
1101
|
this.emit('shutdown');
|
|
1016
1102
|
}
|
|
@@ -1027,10 +1113,6 @@ export class Matterbridge extends EventEmitter {
|
|
|
1027
1113
|
* @returns {Promise<void>} - A promise that resolves when the device is added.
|
|
1028
1114
|
*/
|
|
1029
1115
|
async addBridgedDevice(pluginName, device) {
|
|
1030
|
-
if (this.bridgeMode === 'bridge' && !this.matterAggregator) {
|
|
1031
|
-
this.log.error(`Adding bridged device ${dev}${device.deviceName}${er} (${dev}${device.name}${er}) for plugin ${plg}${pluginName}${er} error: matterAggregator not found`);
|
|
1032
|
-
return;
|
|
1033
|
-
}
|
|
1034
1116
|
this.log.debug(`Adding bridged device ${dev}${device.deviceName}${db} (${dev}${device.name}${db}) for plugin ${plg}${pluginName}${db}`);
|
|
1035
1117
|
// Check if the plugin is registered
|
|
1036
1118
|
const plugin = this.plugins.get(pluginName);
|
|
@@ -1040,12 +1122,17 @@ export class Matterbridge extends EventEmitter {
|
|
|
1040
1122
|
}
|
|
1041
1123
|
// Register and add the device to matterbridge aggregator in bridge mode
|
|
1042
1124
|
if (this.bridgeMode === 'bridge') {
|
|
1043
|
-
this.matterAggregator
|
|
1125
|
+
if (!this.matterAggregator) {
|
|
1126
|
+
this.log.error(`Adding bridged device ${dev}${device.deviceName}${er} (${dev}${device.name}${er}) for plugin ${plg}${pluginName}${er} error: matterAggregator not found`);
|
|
1127
|
+
return;
|
|
1128
|
+
}
|
|
1129
|
+
this.matterAggregator.addBridgedDevice(device);
|
|
1044
1130
|
}
|
|
1045
1131
|
// The first time create the commissioning server and the aggregator for DynamicPlatform
|
|
1046
1132
|
// Register and add the device in childbridge mode
|
|
1047
1133
|
if (this.bridgeMode === 'childbridge') {
|
|
1048
1134
|
if (plugin.type === 'AccessoryPlatform') {
|
|
1135
|
+
// Check if the plugin is locked with the commissioning server
|
|
1049
1136
|
if (!plugin.locked) {
|
|
1050
1137
|
plugin.locked = true;
|
|
1051
1138
|
plugin.storageContext = await this.importCommissioningServerContext(plugin.name, device);
|
|
@@ -1059,10 +1146,10 @@ export class Matterbridge extends EventEmitter {
|
|
|
1059
1146
|
}
|
|
1060
1147
|
}
|
|
1061
1148
|
if (plugin.type === 'DynamicPlatform') {
|
|
1149
|
+
// Check if the plugin is locked with the commissioning server and the aggregator
|
|
1062
1150
|
if (!plugin.locked) {
|
|
1063
1151
|
plugin.locked = true;
|
|
1064
1152
|
this.log.debug(`Creating commissioning server context for ${plg}${plugin.name}${db}`);
|
|
1065
|
-
// plugin.storageContext = await this.createCommissioningServerContext(plugin.name, 'Matterbridge', DeviceTypes.AGGREGATOR.code, 0xfff1, 'Matterbridge', 0x8000, 'Matterbridge Dynamic Platform');
|
|
1066
1153
|
plugin.storageContext = await this.createCommissioningServerContext(plugin.name, 'Matterbridge', DeviceTypes.AGGREGATOR.code, 0xfff1, 'Matterbridge', 0x8000, plugin.description);
|
|
1067
1154
|
this.log.debug(`Creating commissioning server for ${plg}${plugin.name}${db}`);
|
|
1068
1155
|
plugin.commissioningServer = await this.createCommisioningServer(plugin.storageContext, plugin.name);
|
|
@@ -1081,6 +1168,8 @@ export class Matterbridge extends EventEmitter {
|
|
|
1081
1168
|
plugin.registeredDevices++;
|
|
1082
1169
|
if (plugin.addedDevices !== undefined)
|
|
1083
1170
|
plugin.addedDevices++;
|
|
1171
|
+
// Add the device to the DeviceManager
|
|
1172
|
+
this.devices.set(device);
|
|
1084
1173
|
this.log.info(`Added and registered bridged device (${plugin.registeredDevices}/${plugin.addedDevices}) ${dev}${device.deviceName}${nf} (${dev}${device.name}${nf}) for plugin ${plg}${pluginName}${nf}`);
|
|
1085
1174
|
}
|
|
1086
1175
|
/**
|
|
@@ -1090,10 +1179,6 @@ export class Matterbridge extends EventEmitter {
|
|
|
1090
1179
|
* @returns A Promise that resolves when the device is successfully removed.
|
|
1091
1180
|
*/
|
|
1092
1181
|
async removeBridgedDevice(pluginName, device) {
|
|
1093
|
-
if (this.bridgeMode === 'bridge' && !this.matterAggregator) {
|
|
1094
|
-
this.log.error(`Error removing bridged device ${dev}${device.deviceName}${er} (${dev}${device.name}${er}) for plugin ${plg}${pluginName}${er}: matterAggregator not found`);
|
|
1095
|
-
return;
|
|
1096
|
-
}
|
|
1097
1182
|
this.log.debug(`Removing bridged device ${dev}${device.deviceName}${db} (${dev}${device.name}${db}) for plugin ${plg}${pluginName}${db}`);
|
|
1098
1183
|
// Check if the plugin is registered
|
|
1099
1184
|
const plugin = this.plugins.get(pluginName);
|
|
@@ -1101,18 +1186,16 @@ export class Matterbridge extends EventEmitter {
|
|
|
1101
1186
|
this.log.error(`Error removing bridged device ${dev}${device.deviceName}${er} (${dev}${device.name}${er}) for plugin ${plg}${pluginName}${er}: plugin not found`);
|
|
1102
1187
|
return;
|
|
1103
1188
|
}
|
|
1104
|
-
if (this.bridgeMode === 'childbridge' && plugin.type === 'AccessoryPlatfoem' && !plugin.aggregator) {
|
|
1105
|
-
this.log.error(`Error removing bridged device ${dev}${device.deviceName}${er} (${dev}${device.name}${er}) for plugin ${plg}${pluginName}${er}: aggregator not found`);
|
|
1106
|
-
return;
|
|
1107
|
-
}
|
|
1108
|
-
if (this.bridgeMode === 'childbridge' && plugin.type === 'DynamicPlatfoem' && !plugin.commissioningServer) {
|
|
1109
|
-
this.log.error(`Error removing bridged device ${dev}${device.deviceName}${er} (${dev}${device.name}${er}) for plugin ${plg}${pluginName}${er}: commissioning server not found`);
|
|
1110
|
-
return;
|
|
1111
|
-
}
|
|
1112
1189
|
// Remove the device from matterbridge aggregator in bridge mode
|
|
1113
1190
|
if (this.bridgeMode === 'bridge') {
|
|
1191
|
+
if (!this.matterAggregator) {
|
|
1192
|
+
this.log.error(`Error removing bridged device ${dev}${device.deviceName}${er} (${dev}${device.name}${er}) for plugin ${plg}${pluginName}${er}: matterAggregator not found`);
|
|
1193
|
+
return;
|
|
1194
|
+
}
|
|
1114
1195
|
device.setBridgedDeviceReachability(false);
|
|
1115
1196
|
device.getClusterServerById(BridgedDeviceBasicInformation.Cluster.id)?.triggerReachableChangedEvent({ reachableNewValue: false });
|
|
1197
|
+
// device.getClusterServerById(BridgedDeviceBasicInformation.Cluster.id)?.triggerShutDownEvent({});
|
|
1198
|
+
// device.getClusterServerById(BridgedDeviceBasicInformation.Cluster.id)?.triggerLeaveEvent({});
|
|
1116
1199
|
this.matterAggregator?.removeBridgedDevice(device);
|
|
1117
1200
|
this.registeredDevices.forEach((registeredDevice, index) => {
|
|
1118
1201
|
if (registeredDevice.device === device) {
|
|
@@ -1129,6 +1212,10 @@ export class Matterbridge extends EventEmitter {
|
|
|
1129
1212
|
// Remove the device in childbridge mode
|
|
1130
1213
|
if (this.bridgeMode === 'childbridge') {
|
|
1131
1214
|
if (plugin.type === 'AccessoryPlatform') {
|
|
1215
|
+
if (!plugin.commissioningServer) {
|
|
1216
|
+
this.log.error(`Error removing bridged device ${dev}${device.deviceName}${er} (${dev}${device.name}${er}) for plugin ${plg}${pluginName}${er}: commissioning server not found`);
|
|
1217
|
+
return;
|
|
1218
|
+
}
|
|
1132
1219
|
this.registeredDevices.forEach((registeredDevice, index) => {
|
|
1133
1220
|
if (registeredDevice.device === device) {
|
|
1134
1221
|
this.registeredDevices.splice(index, 1);
|
|
@@ -1137,6 +1224,10 @@ export class Matterbridge extends EventEmitter {
|
|
|
1137
1224
|
});
|
|
1138
1225
|
}
|
|
1139
1226
|
else if (plugin.type === 'DynamicPlatform') {
|
|
1227
|
+
if (!plugin.aggregator) {
|
|
1228
|
+
this.log.error(`Error removing bridged device ${dev}${device.deviceName}${er} (${dev}${device.name}${er}) for plugin ${plg}${pluginName}${er}: aggregator not found`);
|
|
1229
|
+
return;
|
|
1230
|
+
}
|
|
1140
1231
|
this.registeredDevices.forEach((registeredDevice, index) => {
|
|
1141
1232
|
if (registeredDevice.device === device) {
|
|
1142
1233
|
this.registeredDevices.splice(index, 1);
|
|
@@ -1145,19 +1236,22 @@ export class Matterbridge extends EventEmitter {
|
|
|
1145
1236
|
});
|
|
1146
1237
|
device.setBridgedDeviceReachability(false);
|
|
1147
1238
|
device.getClusterServerById(BridgedDeviceBasicInformation.Cluster.id)?.triggerReachableChangedEvent({ reachableNewValue: false });
|
|
1148
|
-
plugin.aggregator
|
|
1239
|
+
plugin.aggregator.removeBridgedDevice(device);
|
|
1149
1240
|
}
|
|
1150
1241
|
this.log.info(`Removed bridged device(${plugin.registeredDevices}/${plugin.addedDevices}) ${dev}${device.deviceName}${nf} (${dev}${device.name}${nf}) for plugin ${plg}${pluginName}${nf}`);
|
|
1151
1242
|
if (plugin.registeredDevices !== undefined)
|
|
1152
1243
|
plugin.registeredDevices--;
|
|
1153
1244
|
if (plugin.addedDevices !== undefined)
|
|
1154
1245
|
plugin.addedDevices--;
|
|
1246
|
+
// Remove the commissioning server
|
|
1155
1247
|
if (plugin.registeredDevices === 0 && plugin.addedDevices === 0 && plugin.commissioningServer) {
|
|
1156
1248
|
this.matterServer?.removeCommissioningServer(plugin.commissioningServer);
|
|
1157
1249
|
plugin.commissioningServer = undefined;
|
|
1158
1250
|
this.log.info(`Removed commissioning server for plugin ${plg}${pluginName}${nf}`);
|
|
1159
1251
|
}
|
|
1160
1252
|
}
|
|
1253
|
+
// Remove the device from the DeviceManager
|
|
1254
|
+
this.devices.remove(device);
|
|
1161
1255
|
}
|
|
1162
1256
|
/**
|
|
1163
1257
|
* Removes all bridged devices associated with a specific plugin.
|
|
@@ -1177,304 +1271,6 @@ export class Matterbridge extends EventEmitter {
|
|
|
1177
1271
|
this.removeBridgedDevice(pluginName, registeredDevice.device);
|
|
1178
1272
|
}
|
|
1179
1273
|
}
|
|
1180
|
-
/**
|
|
1181
|
-
* Loads the schema for a plugin.
|
|
1182
|
-
* If the schema file exists in the plugin directory, it reads the file and returns the parsed JSON data and delete the schema form .matterbridge.
|
|
1183
|
-
* If the schema file does not exist, it creates a new schema with the default configuration and returns it.
|
|
1184
|
-
*
|
|
1185
|
-
* @param plugin - The plugin for which to load the schema.
|
|
1186
|
-
* @returns A promise that resolves to the loaded or created schema.
|
|
1187
|
-
*/
|
|
1188
|
-
async loadPluginSchema(plugin) {
|
|
1189
|
-
let schemaFile = plugin.path.replace('package.json', `${plugin.name}.schema.json`);
|
|
1190
|
-
try {
|
|
1191
|
-
await fs.access(schemaFile);
|
|
1192
|
-
const data = await fs.readFile(schemaFile, 'utf8');
|
|
1193
|
-
const schema = JSON.parse(data);
|
|
1194
|
-
schema.title = plugin.description;
|
|
1195
|
-
schema.description = plugin.name + ' v. ' + plugin.version + ' by ' + plugin.author;
|
|
1196
|
-
this.log.debug(`Schema file found: ${schemaFile}.`);
|
|
1197
|
-
// this.log.debug(`Schema file found: ${schemaFile}.\nSchema:${rs}\n`, schema);
|
|
1198
|
-
schemaFile = path.join(this.matterbridgeDirectory, `${plugin.name}.schema.json`);
|
|
1199
|
-
try {
|
|
1200
|
-
await fs.unlink(schemaFile);
|
|
1201
|
-
this.log.debug(`Schema file ${schemaFile} deleted.`);
|
|
1202
|
-
}
|
|
1203
|
-
catch (err) {
|
|
1204
|
-
this.log.debug(`Schema file ${schemaFile} to delete not found.`);
|
|
1205
|
-
}
|
|
1206
|
-
return schema;
|
|
1207
|
-
}
|
|
1208
|
-
catch (err) {
|
|
1209
|
-
this.log.debug(`Schema file ${schemaFile} not found. Loading default schema.`);
|
|
1210
|
-
const schema = {
|
|
1211
|
-
title: plugin.description,
|
|
1212
|
-
description: plugin.name + ' v. ' + plugin.version + ' by ' + plugin.author,
|
|
1213
|
-
type: 'object',
|
|
1214
|
-
properties: {
|
|
1215
|
-
name: {
|
|
1216
|
-
description: 'Plugin name',
|
|
1217
|
-
type: 'string',
|
|
1218
|
-
readOnly: true,
|
|
1219
|
-
},
|
|
1220
|
-
type: {
|
|
1221
|
-
description: 'Plugin type',
|
|
1222
|
-
type: 'string',
|
|
1223
|
-
readOnly: true,
|
|
1224
|
-
},
|
|
1225
|
-
debug: {
|
|
1226
|
-
description: 'Enable the debug for the plugin (development only)',
|
|
1227
|
-
type: 'boolean',
|
|
1228
|
-
default: false,
|
|
1229
|
-
},
|
|
1230
|
-
unregisterOnShutdown: {
|
|
1231
|
-
description: 'Unregister all devices on shutdown (development only)',
|
|
1232
|
-
type: 'boolean',
|
|
1233
|
-
default: false,
|
|
1234
|
-
},
|
|
1235
|
-
},
|
|
1236
|
-
};
|
|
1237
|
-
return schema;
|
|
1238
|
-
}
|
|
1239
|
-
}
|
|
1240
|
-
/**
|
|
1241
|
-
* Loads the configuration for a plugin.
|
|
1242
|
-
* If the configuration file exists, it reads the file and returns the parsed JSON data.
|
|
1243
|
-
* If the configuration file does not exist, it creates a new file with default configuration and returns it.
|
|
1244
|
-
* If any error occurs during file access or creation, it logs an error and return un empty config.
|
|
1245
|
-
*
|
|
1246
|
-
* @param plugin - The plugin for which to load the configuration.
|
|
1247
|
-
* @returns A promise that resolves to the loaded or created configuration.
|
|
1248
|
-
*/
|
|
1249
|
-
async loadPluginConfig(plugin) {
|
|
1250
|
-
const configFile = path.join(this.matterbridgeDirectory, `${plugin.name}.config.json`);
|
|
1251
|
-
try {
|
|
1252
|
-
await fs.access(configFile);
|
|
1253
|
-
const data = await fs.readFile(configFile, 'utf8');
|
|
1254
|
-
const config = JSON.parse(data);
|
|
1255
|
-
this.log.debug(`Config file found: ${configFile}.`);
|
|
1256
|
-
// this.log.debug(`Config file found: ${configFile}.\nConfig:${rs}\n`, config);
|
|
1257
|
-
/* The first time a plugin is added to the system, the config file is created with the plugin name and type "".*/
|
|
1258
|
-
config.name = plugin.name;
|
|
1259
|
-
config.type = plugin.type;
|
|
1260
|
-
if (config.debug === undefined)
|
|
1261
|
-
config.debug = false;
|
|
1262
|
-
if (config.unregisterOnShutdown === undefined)
|
|
1263
|
-
config.unregisterOnShutdown = false;
|
|
1264
|
-
return config;
|
|
1265
|
-
}
|
|
1266
|
-
catch (err) {
|
|
1267
|
-
if (err instanceof Error) {
|
|
1268
|
-
const nodeErr = err;
|
|
1269
|
-
if (nodeErr.code === 'ENOENT') {
|
|
1270
|
-
let config;
|
|
1271
|
-
if (plugin.name === 'matterbridge-zigbee2mqtt')
|
|
1272
|
-
config = zigbee2mqtt_config;
|
|
1273
|
-
else if (plugin.name === 'matterbridge-somfy-tahoma')
|
|
1274
|
-
config = somfytahoma_config;
|
|
1275
|
-
else if (plugin.name === 'matterbridge-shelly')
|
|
1276
|
-
config = shelly_config;
|
|
1277
|
-
else
|
|
1278
|
-
config = { name: plugin.name, type: plugin.type, debug: false, unregisterOnShutdown: false };
|
|
1279
|
-
try {
|
|
1280
|
-
await this.writeFile(configFile, JSON.stringify(config, null, 2));
|
|
1281
|
-
this.log.debug(`Created config file: ${configFile}.`);
|
|
1282
|
-
// this.log.debug(`Created config file: ${configFile}.\nConfig:${rs}\n`, config);
|
|
1283
|
-
return config;
|
|
1284
|
-
}
|
|
1285
|
-
catch (err) {
|
|
1286
|
-
this.log.error(`Error creating config file ${configFile}: ${err}`);
|
|
1287
|
-
return config;
|
|
1288
|
-
}
|
|
1289
|
-
}
|
|
1290
|
-
else {
|
|
1291
|
-
this.log.error(`Error accessing config file ${configFile}: ${err}`);
|
|
1292
|
-
return { name: plugin.name, type: plugin.type, debug: false, unregisterOnShutdown: false };
|
|
1293
|
-
}
|
|
1294
|
-
}
|
|
1295
|
-
this.log.error(`Error loading config file ${configFile}: ${err}`);
|
|
1296
|
-
return { name: plugin.name, type: plugin.type, debug: false, unregisterOnShutdown: false };
|
|
1297
|
-
}
|
|
1298
|
-
}
|
|
1299
|
-
/**
|
|
1300
|
-
* Saves the configuration of a registered plugin.
|
|
1301
|
-
* @param {RegisteredPlugin} plugin - The plugin whose configuration needs to be saved.
|
|
1302
|
-
* @returns {Promise<void>} - A promise that resolves when the configuration is successfully saved.
|
|
1303
|
-
* @throws {Error} - If the plugin's configuration is not found or if there is an error while saving the configuration.
|
|
1304
|
-
*/
|
|
1305
|
-
async savePluginConfig(plugin) {
|
|
1306
|
-
if (!plugin.platform?.config) {
|
|
1307
|
-
this.log.error(`Error saving plugin ${plg}${plugin.name}${er} config: config not found`);
|
|
1308
|
-
return Promise.reject(new Error(`Error saving plugin ${plg}${plugin.name}${er} config: config not found`));
|
|
1309
|
-
}
|
|
1310
|
-
const configFile = path.join(this.matterbridgeDirectory, `${plugin.name}.config.json`);
|
|
1311
|
-
try {
|
|
1312
|
-
await this.writeFile(configFile, JSON.stringify(plugin.platform.config, null, 2));
|
|
1313
|
-
this.log.debug(`Saved config file: ${configFile}.`);
|
|
1314
|
-
// this.log.debug(`Saved config file: ${configFile}.\nConfig:${rs}\n`, plugin.platform.config);
|
|
1315
|
-
}
|
|
1316
|
-
catch (err) {
|
|
1317
|
-
this.log.error(`Error saving plugin ${plg}${plugin.name}${er} config: ${err}`);
|
|
1318
|
-
return Promise.reject(err);
|
|
1319
|
-
}
|
|
1320
|
-
}
|
|
1321
|
-
/**
|
|
1322
|
-
* Writes data to a file.
|
|
1323
|
-
*
|
|
1324
|
-
* @param {string} filePath - The path of the file to write to.
|
|
1325
|
-
* @param {string} data - The data to write to the file.
|
|
1326
|
-
* @returns {Promise<void>} - A promise that resolves when the data is successfully written to the file.
|
|
1327
|
-
*/
|
|
1328
|
-
async writeFile(filePath, data) {
|
|
1329
|
-
try {
|
|
1330
|
-
await fs.writeFile(`${filePath}`, data, 'utf8');
|
|
1331
|
-
this.log.debug(`Successfully wrote to ${filePath}`);
|
|
1332
|
-
}
|
|
1333
|
-
catch (error) {
|
|
1334
|
-
this.log.error(`Error writing to ${filePath}:`, error);
|
|
1335
|
-
}
|
|
1336
|
-
}
|
|
1337
|
-
/**
|
|
1338
|
-
* Loads a plugin and returns the corresponding MatterbridgePlatform instance.
|
|
1339
|
-
* @param plugin - The plugin to load.
|
|
1340
|
-
* @param start - Optional flag indicating whether to start the plugin after loading. Default is false.
|
|
1341
|
-
* @param message - Optional message to pass to the plugin when starting.
|
|
1342
|
-
* @returns A Promise that resolves to the loaded MatterbridgePlatform instance.
|
|
1343
|
-
* @throws An error if the plugin is not enabled, already loaded, or fails to load.
|
|
1344
|
-
*/
|
|
1345
|
-
async loadPlugin(plugin, start = false, message = '') {
|
|
1346
|
-
if (!plugin.enabled) {
|
|
1347
|
-
this.log.error(`Plugin ${plg}${plugin.name}${er} not enabled`);
|
|
1348
|
-
return Promise.resolve(undefined);
|
|
1349
|
-
}
|
|
1350
|
-
if (plugin.platform) {
|
|
1351
|
-
this.log.error(`Plugin ${plg}${plugin.name}${er} already loaded`);
|
|
1352
|
-
return Promise.resolve(plugin.platform);
|
|
1353
|
-
}
|
|
1354
|
-
this.log.info(`Loading plugin ${plg}${plugin.name}${nf} type ${typ}${plugin.type}${nf}`);
|
|
1355
|
-
try {
|
|
1356
|
-
// Load the package.json of the plugin
|
|
1357
|
-
const packageJson = JSON.parse(await fs.readFile(plugin.path, 'utf8'));
|
|
1358
|
-
// Resolve the main module path relative to package.json
|
|
1359
|
-
const pluginEntry = path.resolve(path.dirname(plugin.path), packageJson.main);
|
|
1360
|
-
// Dynamically import the plugin
|
|
1361
|
-
const pluginUrl = pathToFileURL(pluginEntry);
|
|
1362
|
-
this.log.debug(`Importing plugin ${plg}${plugin.name}${db} from ${pluginUrl.href}`);
|
|
1363
|
-
const pluginInstance = await import(pluginUrl.href);
|
|
1364
|
-
this.log.debug(`Imported plugin ${plg}${plugin.name}${db} from ${pluginUrl.href}`);
|
|
1365
|
-
// Call the default export function of the plugin, passing this MatterBridge instance, the log and the config
|
|
1366
|
-
if (pluginInstance.default) {
|
|
1367
|
-
const config = await this.loadPluginConfig(plugin);
|
|
1368
|
-
const log = new AnsiLogger({ logName: plugin.description ?? 'No description', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logDebug: config.debug ?? false });
|
|
1369
|
-
const platform = pluginInstance.default(this, log, config);
|
|
1370
|
-
platform.name = packageJson.name;
|
|
1371
|
-
platform.config = config;
|
|
1372
|
-
platform.version = packageJson.version;
|
|
1373
|
-
plugin.name = packageJson.name;
|
|
1374
|
-
plugin.description = packageJson.description ?? 'No description';
|
|
1375
|
-
plugin.version = packageJson.version;
|
|
1376
|
-
plugin.author = packageJson.author ?? 'Unknown';
|
|
1377
|
-
plugin.type = platform.type;
|
|
1378
|
-
plugin.platform = platform;
|
|
1379
|
-
plugin.loaded = true;
|
|
1380
|
-
plugin.registeredDevices = 0;
|
|
1381
|
-
plugin.addedDevices = 0;
|
|
1382
|
-
plugin.configJson = config;
|
|
1383
|
-
plugin.schemaJson = await this.loadPluginSchema(plugin);
|
|
1384
|
-
this.log.info(`Loaded plugin ${plg}${plugin.name}${nf} type ${typ}${platform.type} ${db}(entrypoint ${UNDERLINE}${pluginEntry}${UNDERLINEOFF})`);
|
|
1385
|
-
if (start)
|
|
1386
|
-
this.startPlugin(plugin, message); // No await do it asyncronously
|
|
1387
|
-
return Promise.resolve(platform);
|
|
1388
|
-
}
|
|
1389
|
-
else {
|
|
1390
|
-
this.log.error(`Plugin ${plg}${plugin.name}${er} does not provide a default export`);
|
|
1391
|
-
plugin.error = true;
|
|
1392
|
-
return Promise.resolve(undefined);
|
|
1393
|
-
}
|
|
1394
|
-
}
|
|
1395
|
-
catch (err) {
|
|
1396
|
-
this.log.error(`Failed to load plugin ${plg}${plugin.name}${er}: ${err}`);
|
|
1397
|
-
plugin.error = true;
|
|
1398
|
-
return Promise.resolve(undefined);
|
|
1399
|
-
}
|
|
1400
|
-
}
|
|
1401
|
-
/**
|
|
1402
|
-
* Starts a plugin.
|
|
1403
|
-
*
|
|
1404
|
-
* @param {RegisteredPlugin} plugin - The plugin to start.
|
|
1405
|
-
* @param {string} [message] - Optional message to pass to the plugin's onStart method.
|
|
1406
|
-
* @param {boolean} [configure] - Indicates whether to configure the plugin after starting (default false).
|
|
1407
|
-
* @returns {Promise<void>} A promise that resolves when the plugin is started successfully, or rejects with an error if starting the plugin fails.
|
|
1408
|
-
*/
|
|
1409
|
-
async startPlugin(plugin, message, configure = false) {
|
|
1410
|
-
if (!plugin.loaded || !plugin.platform) {
|
|
1411
|
-
this.log.error(`Plugin ${plg}${plugin.name}${er} not loaded or no platform`);
|
|
1412
|
-
return Promise.resolve();
|
|
1413
|
-
}
|
|
1414
|
-
if (plugin.started) {
|
|
1415
|
-
this.log.debug(`Plugin ${plg}${plugin.name}${db} already started`);
|
|
1416
|
-
return Promise.resolve();
|
|
1417
|
-
}
|
|
1418
|
-
this.log.info(`Starting plugin ${plg}${plugin.name}${db} type ${typ}${plugin.type}${db}`);
|
|
1419
|
-
try {
|
|
1420
|
-
plugin.platform
|
|
1421
|
-
.onStart(message)
|
|
1422
|
-
.then(() => {
|
|
1423
|
-
plugin.started = true;
|
|
1424
|
-
this.log.info(`Started plugin ${plg}${plugin.name}${db} type ${typ}${plugin.type}${db}`);
|
|
1425
|
-
if (configure)
|
|
1426
|
-
this.configurePlugin(plugin); // No await do it asyncronously
|
|
1427
|
-
return Promise.resolve();
|
|
1428
|
-
})
|
|
1429
|
-
.catch((err) => {
|
|
1430
|
-
plugin.error = true;
|
|
1431
|
-
this.log.error(`Failed to start plugin ${plg}${plugin.name}${er}: ${err}`);
|
|
1432
|
-
return Promise.resolve();
|
|
1433
|
-
});
|
|
1434
|
-
}
|
|
1435
|
-
catch (err) {
|
|
1436
|
-
plugin.error = true;
|
|
1437
|
-
this.log.error(`Failed to start plugin ${plg}${plugin.name}${er}: ${err}`);
|
|
1438
|
-
return Promise.resolve();
|
|
1439
|
-
}
|
|
1440
|
-
}
|
|
1441
|
-
/**
|
|
1442
|
-
* Configures a plugin.
|
|
1443
|
-
*
|
|
1444
|
-
* @param {RegisteredPlugin} plugin - The plugin to configure.
|
|
1445
|
-
* @returns {Promise<void>} A promise that resolves when the plugin is configured successfully, or rejects with an error if configuration fails.
|
|
1446
|
-
*/
|
|
1447
|
-
async configurePlugin(plugin) {
|
|
1448
|
-
if (!plugin.loaded || !plugin.started || !plugin.platform) {
|
|
1449
|
-
this.log.error(`Plugin ${plg}${plugin.name}${er} not loaded (${plugin.loaded}) or not started (${plugin.started}) or not platform (${plugin.platform?.name})`);
|
|
1450
|
-
return Promise.resolve();
|
|
1451
|
-
}
|
|
1452
|
-
if (plugin.configured) {
|
|
1453
|
-
this.log.info(`Plugin ${plg}${plugin.name}${nf} already configured`);
|
|
1454
|
-
return Promise.resolve();
|
|
1455
|
-
}
|
|
1456
|
-
this.log.info(`Configuring plugin ${plg}${plugin.name}${nf} type ${typ}${plugin.type}${nf}`);
|
|
1457
|
-
try {
|
|
1458
|
-
plugin.platform
|
|
1459
|
-
.onConfigure()
|
|
1460
|
-
.then(() => {
|
|
1461
|
-
plugin.configured = true;
|
|
1462
|
-
this.log.info(`Configured plugin ${plg}${plugin.name}${nf} type ${typ}${plugin.type}${nf}`);
|
|
1463
|
-
this.savePluginConfig(plugin);
|
|
1464
|
-
return Promise.resolve();
|
|
1465
|
-
})
|
|
1466
|
-
.catch((err) => {
|
|
1467
|
-
plugin.error = true;
|
|
1468
|
-
this.log.error(`Failed to configure plugin ${plg}${plugin.name}${er}: ${err}`);
|
|
1469
|
-
return Promise.resolve();
|
|
1470
|
-
});
|
|
1471
|
-
}
|
|
1472
|
-
catch (err) {
|
|
1473
|
-
plugin.error = true;
|
|
1474
|
-
this.log.error(`Failed to configure plugin ${plg}${plugin.name}${er}: ${err}`);
|
|
1475
|
-
return Promise.resolve();
|
|
1476
|
-
}
|
|
1477
|
-
}
|
|
1478
1274
|
async startTest() {
|
|
1479
1275
|
// Start the Matterbridge
|
|
1480
1276
|
}
|
|
@@ -1514,14 +1310,14 @@ export class Matterbridge extends EventEmitter {
|
|
|
1514
1310
|
clearInterval(startMatterInterval);
|
|
1515
1311
|
this.log.debug('***Cleared startMatterInterval interval for Matterbridge');
|
|
1516
1312
|
await this.startMatterServer();
|
|
1517
|
-
this.log.
|
|
1313
|
+
this.log.notice('Matter server started');
|
|
1518
1314
|
// Configure the plugins
|
|
1519
1315
|
this.configureTimeout = setTimeout(async () => {
|
|
1520
1316
|
for (const plugin of this.plugins) {
|
|
1521
1317
|
if (!plugin.enabled || !plugin.loaded || !plugin.started || plugin.error)
|
|
1522
1318
|
continue;
|
|
1523
1319
|
try {
|
|
1524
|
-
await this.plugins.configure(plugin); // No await do it
|
|
1320
|
+
await this.plugins.configure(plugin); // TODO No await do it in parallel
|
|
1525
1321
|
}
|
|
1526
1322
|
catch (error) {
|
|
1527
1323
|
plugin.error = true;
|
|
@@ -1582,14 +1378,14 @@ export class Matterbridge extends EventEmitter {
|
|
|
1582
1378
|
clearInterval(startMatterInterval);
|
|
1583
1379
|
this.log.debug('***Cleared startMatterInterval interval in childbridge mode');
|
|
1584
1380
|
await this.startMatterServer();
|
|
1585
|
-
this.log.
|
|
1381
|
+
this.log.notice('Matter server started');
|
|
1586
1382
|
// Configure the plugins
|
|
1587
1383
|
this.configureTimeout = setTimeout(async () => {
|
|
1588
1384
|
for (const plugin of this.plugins) {
|
|
1589
1385
|
if (!plugin.enabled || !plugin.loaded || !plugin.started || plugin.error)
|
|
1590
1386
|
continue;
|
|
1591
1387
|
try {
|
|
1592
|
-
await this.plugins.configure(plugin); // No await do it
|
|
1388
|
+
await this.plugins.configure(plugin); // TODO No await do it in parallel
|
|
1593
1389
|
}
|
|
1594
1390
|
catch (error) {
|
|
1595
1391
|
plugin.error = true;
|
|
@@ -1815,7 +1611,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
1815
1611
|
* @param {string} storageName - The name of the storage file.
|
|
1816
1612
|
* @returns {Promise<void>} - A promise that resolves when the storage process is started.
|
|
1817
1613
|
*/
|
|
1818
|
-
async
|
|
1614
|
+
async startMatterStorage(storageType, storageName) {
|
|
1819
1615
|
this.log.debug(`Starting ${storageType} storage ${CYAN}${storageName}${db}`);
|
|
1820
1616
|
if (storageType === 'disk') {
|
|
1821
1617
|
const storageDisk = new StorageBackendDisk(storageName);
|
|
@@ -1836,8 +1632,9 @@ export class Matterbridge extends EventEmitter {
|
|
|
1836
1632
|
await this.storageManager.initialize();
|
|
1837
1633
|
this.log.debug('Storage initialized');
|
|
1838
1634
|
if (storageType === 'json') {
|
|
1839
|
-
await this.
|
|
1635
|
+
await this.backupJsonMatterStorage(storageName, storageName.replace('.json', '') + '.backup.json');
|
|
1840
1636
|
}
|
|
1637
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1841
1638
|
}
|
|
1842
1639
|
catch (error) {
|
|
1843
1640
|
this.log.error(`Storage initialize() error! The file .matterbridge/${storageName} may be corrupted.`);
|
|
@@ -1851,7 +1648,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
1851
1648
|
* @param storageName - The name of the JSON storage file to be backed up.
|
|
1852
1649
|
* @param backupName - The name of the backup file to be created.
|
|
1853
1650
|
*/
|
|
1854
|
-
async
|
|
1651
|
+
async backupJsonMatterStorage(storageName, backupName) {
|
|
1855
1652
|
try {
|
|
1856
1653
|
this.log.debug(`Making backup copy of ${storageName}`);
|
|
1857
1654
|
await fs.copyFile(storageName, backupName);
|
|
@@ -1875,7 +1672,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
1875
1672
|
* Stops the matter storage.
|
|
1876
1673
|
* @returns {Promise<void>} A promise that resolves when the storage is stopped.
|
|
1877
1674
|
*/
|
|
1878
|
-
async
|
|
1675
|
+
async stopMatterStorage() {
|
|
1879
1676
|
this.log.debug('Stopping storage');
|
|
1880
1677
|
await this.storageManager?.close();
|
|
1881
1678
|
this.log.debug('Storage closed');
|
|
@@ -2028,9 +1825,9 @@ export class Matterbridge extends EventEmitter {
|
|
|
2028
1825
|
const sessionInformations = commissioningServer.getActiveSessionInformation(fabricIndex);
|
|
2029
1826
|
let connected = false;
|
|
2030
1827
|
sessionInformations.forEach((session) => {
|
|
2031
|
-
this.log.info(
|
|
1828
|
+
this.log.info(`Active session changed on fabric ${zb}${fabricIndex}${nf} id ${zb}${session.fabric?.fabricId}${nf} vendor ${zb}${session.fabric?.rootVendorId}${nf} ${this.getVendorIdName(session.fabric?.rootVendorId)} ${session.fabric?.label} for ${plg}${pluginName}${nf}`, debugStringify(session));
|
|
2032
1829
|
if (session.isPeerActive === true && session.secure === true && session.numberOfActiveSubscriptions >= 1) {
|
|
2033
|
-
this.log.
|
|
1830
|
+
this.log.notice(`Controller ${zb}${session.fabric?.rootVendorId}${nt} ${this.getVendorIdName(session.fabric?.rootVendorId)} ${session.fabric?.label} connected to ${plg}${pluginName}${nt} on session ${session.name}`);
|
|
2034
1831
|
connected = true;
|
|
2035
1832
|
}
|
|
2036
1833
|
});
|
|
@@ -2081,9 +1878,9 @@ export class Matterbridge extends EventEmitter {
|
|
|
2081
1878
|
},
|
|
2082
1879
|
commissioningChangedCallback: async (fabricIndex) => {
|
|
2083
1880
|
const fabricInfo = commissioningServer.getCommissionedFabricInformation(fabricIndex);
|
|
2084
|
-
this.log.debug(
|
|
1881
|
+
this.log.debug(`Commissioning changed on fabric ${zb}${fabricIndex}${db} for ${plg}${pluginName}${db}`, debugStringify(fabricInfo));
|
|
2085
1882
|
if (commissioningServer.getCommissionedFabricInformation().length === 0) {
|
|
2086
|
-
this.log.warn(
|
|
1883
|
+
this.log.warn(`Commissioning removed from fabric ${zb}${fabricIndex}${wr} for ${plg}${pluginName}${wr}. Resetting the commissioning server ...`);
|
|
2087
1884
|
await commissioningServer.factoryReset();
|
|
2088
1885
|
if (pluginName === 'Matterbridge') {
|
|
2089
1886
|
await this.matterbridgeContext?.clearAll();
|
|
@@ -2104,7 +1901,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
2104
1901
|
}
|
|
2105
1902
|
}
|
|
2106
1903
|
}
|
|
2107
|
-
this.log.warn(
|
|
1904
|
+
this.log.warn(`Restart to activate the pairing for ${plg}${pluginName}${wr}.`);
|
|
2108
1905
|
}
|
|
2109
1906
|
else {
|
|
2110
1907
|
const fabricInfo = commissioningServer.getCommissionedFabricInformation();
|
|
@@ -2282,7 +2079,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
2282
2079
|
}
|
|
2283
2080
|
}
|
|
2284
2081
|
/**
|
|
2285
|
-
* Sanitizes the fabric information by converting bigint properties to string cause res
|
|
2082
|
+
* Sanitizes the fabric information by converting bigint properties to string cause res.json doesn't know bigint.
|
|
2286
2083
|
*
|
|
2287
2084
|
* @param fabricInfo - The array of exposed fabric information objects.
|
|
2288
2085
|
* @returns An array of sanitized exposed fabric information objects.
|
|
@@ -2414,10 +2211,9 @@ export class Matterbridge extends EventEmitter {
|
|
|
2414
2211
|
};
|
|
2415
2212
|
/**
|
|
2416
2213
|
* Retrieves the base registered plugins sanitized for res.json().
|
|
2417
|
-
* @param {boolean} includeAll - Whether to include all information for each plugin.
|
|
2418
2214
|
* @returns {BaseRegisteredPlugin[]} A promise that resolves to an array of BaseRegisteredPlugin objects.
|
|
2419
2215
|
*/
|
|
2420
|
-
async getBaseRegisteredPlugins(
|
|
2216
|
+
async getBaseRegisteredPlugins() {
|
|
2421
2217
|
const baseRegisteredPlugins = [];
|
|
2422
2218
|
for (const plugin of this.plugins) {
|
|
2423
2219
|
baseRegisteredPlugins.push({
|
|
@@ -2436,23 +2232,23 @@ export class Matterbridge extends EventEmitter {
|
|
|
2436
2232
|
configured: plugin.configured,
|
|
2437
2233
|
paired: plugin.paired,
|
|
2438
2234
|
connected: plugin.connected,
|
|
2439
|
-
fabricInformations:
|
|
2440
|
-
sessionInformations:
|
|
2235
|
+
fabricInformations: plugin.fabricInformations,
|
|
2236
|
+
sessionInformations: plugin.sessionInformations,
|
|
2441
2237
|
registeredDevices: plugin.registeredDevices,
|
|
2442
2238
|
addedDevices: plugin.addedDevices,
|
|
2443
2239
|
qrPairingCode: plugin.qrPairingCode,
|
|
2444
2240
|
manualPairingCode: plugin.manualPairingCode,
|
|
2445
|
-
configJson:
|
|
2446
|
-
schemaJson:
|
|
2241
|
+
configJson: plugin.configJson,
|
|
2242
|
+
schemaJson: plugin.schemaJson,
|
|
2447
2243
|
});
|
|
2448
2244
|
}
|
|
2449
2245
|
return baseRegisteredPlugins;
|
|
2450
2246
|
}
|
|
2451
2247
|
/**
|
|
2452
2248
|
* Spawns a child process with the given command and arguments.
|
|
2453
|
-
* @param command - The command to execute.
|
|
2454
|
-
* @param args - The arguments to pass to the command (default: []).
|
|
2455
|
-
* @returns A promise that resolves when the child process exits successfully, or rejects if there is an error.
|
|
2249
|
+
* @param {string} command - The command to execute.
|
|
2250
|
+
* @param {string[]} args - The arguments to pass to the command (default: []).
|
|
2251
|
+
* @returns {Promise<void>} A promise that resolves when the child process exits successfully, or rejects if there is an error.
|
|
2456
2252
|
*/
|
|
2457
2253
|
async spawnCommand(command, args = []) {
|
|
2458
2254
|
/*
|
|
@@ -2462,7 +2258,13 @@ export class Matterbridge extends EventEmitter {
|
|
|
2462
2258
|
process.on('unhandledRejection', (reason, promise) => {
|
|
2463
2259
|
this.log.error('Unhandled Rejection at:', promise, 'reason:', reason);
|
|
2464
2260
|
});
|
|
2261
|
+
|
|
2262
|
+
spawn - [14:27:21.125] [Matterbridge:spawn]: changed 38 packages in 4s
|
|
2263
|
+
spawn - [14:27:21.125] [Matterbridge:spawn]: 10 packages are looking for funding run `npm fund` for details
|
|
2264
|
+
debug - [14:27:21.131] [Matterbridge]: Child process exited with code 0 and signal null
|
|
2265
|
+
debug - [14:27:21.131] [Matterbridge]: Child process stdio streams have closed with code 0
|
|
2465
2266
|
*/
|
|
2267
|
+
const cmdLine = command + ' ' + args.join(' ');
|
|
2466
2268
|
if (process.platform === 'win32' && command === 'npm') {
|
|
2467
2269
|
// Must be spawn('cmd.exe', ['/c', 'npm -g install <package>']);
|
|
2468
2270
|
const argstring = 'npm ' + args.join(' ');
|
|
@@ -2482,9 +2284,11 @@ export class Matterbridge extends EventEmitter {
|
|
|
2482
2284
|
this.log.error(`Failed to start child process: ${err.message}`);
|
|
2483
2285
|
reject(err); // Reject the promise on error
|
|
2484
2286
|
});
|
|
2485
|
-
childProcess.on('close', (code) => {
|
|
2287
|
+
childProcess.on('close', (code, signal) => {
|
|
2288
|
+
this.wssSendMessage('spawn', this.log.now(), 'Matterbridge:spawn', `child process closed with code ${code} and signal ${signal}`);
|
|
2486
2289
|
if (code === 0) {
|
|
2487
|
-
|
|
2290
|
+
if (cmdLine.startsWith('npm install -g'))
|
|
2291
|
+
this.log.notice(`${cmdLine.replace('npm install -g ', '')} installed correctly`);
|
|
2488
2292
|
resolve();
|
|
2489
2293
|
}
|
|
2490
2294
|
else {
|
|
@@ -2493,8 +2297,8 @@ export class Matterbridge extends EventEmitter {
|
|
|
2493
2297
|
}
|
|
2494
2298
|
});
|
|
2495
2299
|
childProcess.on('exit', (code, signal) => {
|
|
2300
|
+
this.wssSendMessage('spawn', this.log.now(), 'Matterbridge:spawn', `child process exited with code ${code} and signal ${signal}`);
|
|
2496
2301
|
if (code === 0) {
|
|
2497
|
-
this.log.debug(`Child process exited with code ${code} and signal ${signal}`);
|
|
2498
2302
|
resolve();
|
|
2499
2303
|
}
|
|
2500
2304
|
else {
|
|
@@ -2509,15 +2313,13 @@ export class Matterbridge extends EventEmitter {
|
|
|
2509
2313
|
if (childProcess.stdout) {
|
|
2510
2314
|
childProcess.stdout.on('data', (data) => {
|
|
2511
2315
|
const message = data.toString().trim();
|
|
2512
|
-
|
|
2513
|
-
this.wssSendMessage('Matterbridge:spawn', 'spawn', message);
|
|
2316
|
+
this.wssSendMessage('spawn', this.log.now(), 'Matterbridge:spawn', message);
|
|
2514
2317
|
});
|
|
2515
2318
|
}
|
|
2516
2319
|
if (childProcess.stderr) {
|
|
2517
2320
|
childProcess.stderr.on('data', (data) => {
|
|
2518
2321
|
const message = data.toString().trim();
|
|
2519
|
-
|
|
2520
|
-
this.wssSendMessage('Matterbridge:spawn', 'spawn', message);
|
|
2322
|
+
this.wssSendMessage('spawn', this.log.now(), 'Matterbridge:spawn', message);
|
|
2521
2323
|
});
|
|
2522
2324
|
}
|
|
2523
2325
|
});
|
|
@@ -2525,20 +2327,45 @@ export class Matterbridge extends EventEmitter {
|
|
|
2525
2327
|
/**
|
|
2526
2328
|
* Sends a WebSocket message to all connected clients.
|
|
2527
2329
|
*
|
|
2528
|
-
* @param {string}
|
|
2529
|
-
* @param {string}
|
|
2330
|
+
* @param {string} level - The logger level of the message: debug info notice warn error fatal...
|
|
2331
|
+
* @param {string} time - The time string of the message
|
|
2332
|
+
* @param {string} name - The logger name of the message
|
|
2530
2333
|
* @param {string} message - The content of the message.
|
|
2531
2334
|
*/
|
|
2532
|
-
wssSendMessage(
|
|
2335
|
+
wssSendMessage(level, time, name, message) {
|
|
2336
|
+
if (!level || !time || !name || !message)
|
|
2337
|
+
return;
|
|
2533
2338
|
// Remove ANSI escape codes from the message
|
|
2534
2339
|
// eslint-disable-next-line no-control-regex
|
|
2535
|
-
|
|
2340
|
+
message = message.replace(/\x1B\[[0-9;]*[m|s|u|K]/g, '');
|
|
2536
2341
|
// Remove leading asterisks from the message
|
|
2537
|
-
|
|
2342
|
+
message = message.replace(/^\*+/, '');
|
|
2343
|
+
// Replace all occurrences of \t and \n
|
|
2344
|
+
message = message.replace(/[\t\n]/g, '');
|
|
2345
|
+
// Remove non-printable characters
|
|
2346
|
+
// eslint-disable-next-line no-control-regex
|
|
2347
|
+
message = message.replace(/[\x00-\x1F\x7F]/g, '');
|
|
2348
|
+
// Replace all occurrences of \" with "
|
|
2349
|
+
message = message.replace(/\\"/g, '"');
|
|
2350
|
+
// Define the maximum allowed length for continuous characters without a space
|
|
2351
|
+
const maxContinuousLength = 100;
|
|
2352
|
+
const keepStartLength = 20;
|
|
2353
|
+
const keepEndLength = 20;
|
|
2354
|
+
// Split the message into words
|
|
2355
|
+
message = message
|
|
2356
|
+
.split(' ')
|
|
2357
|
+
.map((word) => {
|
|
2358
|
+
// If the word length exceeds the max continuous length, insert spaces and truncate
|
|
2359
|
+
if (word.length > maxContinuousLength) {
|
|
2360
|
+
return word.slice(0, keepStartLength) + ' ... ' + word.slice(-keepEndLength);
|
|
2361
|
+
}
|
|
2362
|
+
return word;
|
|
2363
|
+
})
|
|
2364
|
+
.join(' ');
|
|
2538
2365
|
// Send the message to all connected clients
|
|
2539
2366
|
this.webSocketServer?.clients.forEach((client) => {
|
|
2540
2367
|
if (client.readyState === WebSocket.OPEN) {
|
|
2541
|
-
client.send(JSON.stringify({
|
|
2368
|
+
client.send(JSON.stringify({ level, time, name, message }));
|
|
2542
2369
|
}
|
|
2543
2370
|
});
|
|
2544
2371
|
}
|
|
@@ -2639,17 +2466,17 @@ export class Matterbridge extends EventEmitter {
|
|
|
2639
2466
|
this.webSocketServer = new WebSocketServer(hasParameter('ssl') ? { server: this.httpsServer } : { server: this.httpServer });
|
|
2640
2467
|
this.webSocketServer.on('connection', (ws, request) => {
|
|
2641
2468
|
const clientIp = request.socket.remoteAddress;
|
|
2642
|
-
this.
|
|
2643
|
-
this.log.setGlobalCallback(this.wssSendMessage.bind(this));
|
|
2469
|
+
AnsiLogger.setGlobalCallback(this.wssSendMessage.bind(this), "debug" /* LogLevel.DEBUG */);
|
|
2644
2470
|
this.log.debug('WebSocketServer logger global callback added');
|
|
2645
|
-
this.
|
|
2471
|
+
this.log.info(`WebSocketServer client "${clientIp}" connected to Matterbridge`);
|
|
2472
|
+
// this.wssSendMessage('info', this.log.now(), 'Matterbridge', `WebSocketServer client "${clientIp}" connected to Matterbridge`);
|
|
2646
2473
|
ws.on('message', (message) => {
|
|
2647
2474
|
this.log.debug(`WebSocket client message: ${message}`);
|
|
2648
2475
|
});
|
|
2649
2476
|
ws.on('close', () => {
|
|
2650
2477
|
this.log.info('WebSocket client disconnected');
|
|
2651
2478
|
if (this.webSocketServer?.clients.size === 0) {
|
|
2652
|
-
|
|
2479
|
+
AnsiLogger.setGlobalCallback(undefined);
|
|
2653
2480
|
this.log.debug('All WebSocket clients disconnected. WebSocketServer logger global callback removed');
|
|
2654
2481
|
}
|
|
2655
2482
|
});
|
|
@@ -2685,6 +2512,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
2685
2512
|
this.log.warn('/api/login error wrong password');
|
|
2686
2513
|
res.json({ valid: false });
|
|
2687
2514
|
}
|
|
2515
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
2688
2516
|
}
|
|
2689
2517
|
catch (error) {
|
|
2690
2518
|
this.log.error('/api/login error getting password');
|
|
@@ -2704,6 +2532,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
2704
2532
|
try {
|
|
2705
2533
|
qrPairingCode = await this.matterbridgeContext.get('qrPairingCode');
|
|
2706
2534
|
manualPairingCode = await this.matterbridgeContext.get('manualPairingCode');
|
|
2535
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
2707
2536
|
}
|
|
2708
2537
|
catch (error) {
|
|
2709
2538
|
if (this.bridgeMode === 'bridge')
|
|
@@ -2711,26 +2540,28 @@ export class Matterbridge extends EventEmitter {
|
|
|
2711
2540
|
}
|
|
2712
2541
|
this.matterbridgeInformation.bridgeMode = this.bridgeMode;
|
|
2713
2542
|
this.matterbridgeInformation.restartMode = this.restartMode;
|
|
2714
|
-
this.matterbridgeInformation.
|
|
2543
|
+
this.matterbridgeInformation.loggerLevel = this.log.logLevel;
|
|
2715
2544
|
this.matterbridgeInformation.matterLoggerLevel = Logger.defaultLogLevel;
|
|
2716
2545
|
this.matterbridgeInformation.matterbridgePaired = this.matterbridgePaired;
|
|
2717
2546
|
this.matterbridgeInformation.matterbridgeConnected = this.matterbridgeConnected;
|
|
2718
2547
|
this.matterbridgeInformation.matterbridgeFabricInformations = this.matterbridgeFabricInformations;
|
|
2719
2548
|
this.matterbridgeInformation.matterbridgeSessionInformations = this.matterbridgeSessionInformations;
|
|
2720
|
-
|
|
2549
|
+
if (this.profile)
|
|
2550
|
+
this.matterbridgeInformation.profile = this.profile;
|
|
2551
|
+
const response = { wssHost, ssl: hasParameter('ssl'), qrPairingCode, manualPairingCode, systemInformation: this.systemInformation, matterbridgeInformation: this.matterbridgeInformation };
|
|
2721
2552
|
// this.log.debug('Response:', debugStringify(response));
|
|
2722
|
-
|
|
2723
|
-
this.
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
this.log.debug('WebSocketServer logger global callback added');
|
|
2553
|
+
/*
|
|
2554
|
+
if (this.webSocketServer && this.webSocketServer.clients.size > 0 && !AnsiLogger.getGlobalCallback()) {
|
|
2555
|
+
AnsiLogger.setGlobalCallback(this.wssSendMessage.bind(this), LogLevel.DEBUG);
|
|
2556
|
+
this.log.debug('WebSocketServer logger global callback added');
|
|
2727
2557
|
}
|
|
2558
|
+
*/
|
|
2728
2559
|
res.json(response);
|
|
2729
2560
|
});
|
|
2730
2561
|
// Endpoint to provide plugins
|
|
2731
2562
|
this.expressApp.get('/api/plugins', async (req, res) => {
|
|
2732
2563
|
this.log.debug('The frontend sent /api/plugins');
|
|
2733
|
-
const response = await this.getBaseRegisteredPlugins(
|
|
2564
|
+
const response = await this.getBaseRegisteredPlugins();
|
|
2734
2565
|
// this.log.debug('Response:', debugStringify(response));
|
|
2735
2566
|
res.json(response);
|
|
2736
2567
|
});
|
|
@@ -2837,6 +2668,39 @@ export class Matterbridge extends EventEmitter {
|
|
|
2837
2668
|
});
|
|
2838
2669
|
res.json(data);
|
|
2839
2670
|
});
|
|
2671
|
+
// Endpoint to send the log
|
|
2672
|
+
this.expressApp.get('/api/view-log', async (req, res) => {
|
|
2673
|
+
this.log.debug('The frontend sent /api/log');
|
|
2674
|
+
try {
|
|
2675
|
+
const data = await fs.readFile(path.join(this.matterbridgeDirectory, this.matterbrideLoggerFile), 'utf8');
|
|
2676
|
+
res.type('text/plain');
|
|
2677
|
+
res.send(data);
|
|
2678
|
+
}
|
|
2679
|
+
catch (error) {
|
|
2680
|
+
this.log.error(`Error reading log file ${this.matterbrideLoggerFile}: ${error instanceof Error ? error.message : error}`);
|
|
2681
|
+
res.status(500).send('Error reading log file');
|
|
2682
|
+
}
|
|
2683
|
+
});
|
|
2684
|
+
// Endpoint to download the log
|
|
2685
|
+
this.expressApp.get('/api/download-mblog', (req, res) => {
|
|
2686
|
+
this.log.debug('The frontend sent /api/download-mblog');
|
|
2687
|
+
res.download(path.join(this.matterbridgeDirectory, this.matterbrideLoggerFile), 'matterbridge.log', (error) => {
|
|
2688
|
+
if (error) {
|
|
2689
|
+
this.log.error(`Error downloading log file ${this.matterbrideLoggerFile}: ${error instanceof Error ? error.message : error}`);
|
|
2690
|
+
res.status(500).send('Error downloading the matterbridge log file');
|
|
2691
|
+
}
|
|
2692
|
+
});
|
|
2693
|
+
});
|
|
2694
|
+
// Endpoint to download the log
|
|
2695
|
+
this.expressApp.get('/api/download-mjlog', (req, res) => {
|
|
2696
|
+
this.log.debug('The frontend sent /api/download-mjlog');
|
|
2697
|
+
res.download(path.join(this.matterbridgeDirectory, this.matterLoggerFile), 'matter.log', (error) => {
|
|
2698
|
+
if (error) {
|
|
2699
|
+
this.log.error(`Error downloading log file ${this.matterLoggerFile}: ${error instanceof Error ? error.message : error}`);
|
|
2700
|
+
res.status(500).send('Error downloading the matter log file');
|
|
2701
|
+
}
|
|
2702
|
+
});
|
|
2703
|
+
});
|
|
2840
2704
|
// Endpoint to receive commands
|
|
2841
2705
|
this.expressApp.post('/api/command/:command/:param', express.json(), async (req, res) => {
|
|
2842
2706
|
const command = req.params.command;
|
|
@@ -2859,12 +2723,31 @@ export class Matterbridge extends EventEmitter {
|
|
|
2859
2723
|
if (command === 'setmbloglevel') {
|
|
2860
2724
|
this.log.debug('Matterbridge log level:', param);
|
|
2861
2725
|
if (param === 'Debug') {
|
|
2862
|
-
this.log.
|
|
2863
|
-
this.debugEnabled = true;
|
|
2726
|
+
this.log.logLevel = "debug" /* LogLevel.DEBUG */;
|
|
2864
2727
|
}
|
|
2865
2728
|
else if (param === 'Info') {
|
|
2866
|
-
this.log.
|
|
2867
|
-
|
|
2729
|
+
this.log.logLevel = "info" /* LogLevel.INFO */;
|
|
2730
|
+
}
|
|
2731
|
+
else if (param === 'Notice') {
|
|
2732
|
+
this.log.logLevel = "notice" /* LogLevel.NOTICE */;
|
|
2733
|
+
}
|
|
2734
|
+
else if (param === 'Warn') {
|
|
2735
|
+
this.log.logLevel = "warn" /* LogLevel.WARN */;
|
|
2736
|
+
}
|
|
2737
|
+
else if (param === 'Error') {
|
|
2738
|
+
this.log.logLevel = "error" /* LogLevel.ERROR */;
|
|
2739
|
+
}
|
|
2740
|
+
else if (param === 'Fatal') {
|
|
2741
|
+
this.log.logLevel = "fatal" /* LogLevel.FATAL */;
|
|
2742
|
+
}
|
|
2743
|
+
await this.nodeContext?.set('matterbridgeLogLevel', this.log.logLevel);
|
|
2744
|
+
MatterbridgeDevice.logLevel = this.log.logLevel;
|
|
2745
|
+
this.plugins.logLevel = this.log.logLevel;
|
|
2746
|
+
for (const plugin of this.plugins) {
|
|
2747
|
+
if (!plugin.platform || !plugin.platform.config)
|
|
2748
|
+
continue;
|
|
2749
|
+
plugin.platform.log.logLevel = plugin.platform.config.debug ? "debug" /* LogLevel.DEBUG */ : this.log.logLevel;
|
|
2750
|
+
await plugin.platform.onChangeLoggerLevel(plugin.platform.config.debug ? "debug" /* LogLevel.DEBUG */ : this.log.logLevel);
|
|
2868
2751
|
}
|
|
2869
2752
|
res.json({ message: 'Command received' });
|
|
2870
2753
|
return;
|
|
@@ -2890,6 +2773,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
2890
2773
|
else if (param === 'Fatal') {
|
|
2891
2774
|
Logger.defaultLogLevel = Level.FATAL;
|
|
2892
2775
|
}
|
|
2776
|
+
await this.nodeContext?.set('matterLogLevel', Logger.defaultLogLevel);
|
|
2893
2777
|
res.json({ message: 'Command received' });
|
|
2894
2778
|
return;
|
|
2895
2779
|
}
|
|
@@ -2929,6 +2813,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
2929
2813
|
try {
|
|
2930
2814
|
await this.spawnCommand('npm', ['install', '-g', 'matterbridge']);
|
|
2931
2815
|
this.log.info('Matterbridge has been updated. Full restart required.');
|
|
2816
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
2932
2817
|
}
|
|
2933
2818
|
catch (error) {
|
|
2934
2819
|
this.log.error('Error updating matterbridge');
|
|
@@ -2961,6 +2846,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
2961
2846
|
try {
|
|
2962
2847
|
await this.spawnCommand('npm', ['install', '-g', param]);
|
|
2963
2848
|
this.log.info(`Plugin ${plg}${param}${nf} installed. Full restart required.`);
|
|
2849
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
2964
2850
|
}
|
|
2965
2851
|
catch (error) {
|
|
2966
2852
|
this.log.error(`Error installing plugin ${plg}${param}${er}`);
|
|
@@ -2975,12 +2861,6 @@ export class Matterbridge extends EventEmitter {
|
|
|
2975
2861
|
const plugin = await this.plugins.add(param);
|
|
2976
2862
|
if (plugin) {
|
|
2977
2863
|
this.plugins.load(plugin, true, 'The plugin has been added', true); // No await do it in the background
|
|
2978
|
-
/*
|
|
2979
|
-
plugin.platform = await this.plugins.load(plugin, false, 'The plugin has been added');
|
|
2980
|
-
if (plugin.platform) {
|
|
2981
|
-
await this.plugins.start(plugin, 'The plugin has been added', true);
|
|
2982
|
-
}
|
|
2983
|
-
*/
|
|
2984
2864
|
}
|
|
2985
2865
|
res.json({ message: 'Command received' });
|
|
2986
2866
|
return;
|
|
@@ -3017,12 +2897,6 @@ export class Matterbridge extends EventEmitter {
|
|
|
3017
2897
|
plugin.addedDevices = undefined;
|
|
3018
2898
|
await this.plugins.enable(param);
|
|
3019
2899
|
this.plugins.load(plugin, true, 'The plugin has been enabled', true); // No await do it in the background
|
|
3020
|
-
/*
|
|
3021
|
-
plugin.platform = await this.plugins.load(plugin, false, 'The plugin has been enabled');
|
|
3022
|
-
if (plugin.platform) {
|
|
3023
|
-
await this.plugins.start(plugin, 'The plugin has been enabled', true);
|
|
3024
|
-
}
|
|
3025
|
-
*/
|
|
3026
2900
|
}
|
|
3027
2901
|
}
|
|
3028
2902
|
res.json({ message: 'Command received' });
|
|
@@ -3053,9 +2927,9 @@ export class Matterbridge extends EventEmitter {
|
|
|
3053
2927
|
this.log.debug(`Frontend initialized on port ${YELLOW}${port}${db} static ${UNDERLINE}${path.join(this.rootDirectory, 'frontend/build')}${UNDERLINEOFF}${rs}`);
|
|
3054
2928
|
}
|
|
3055
2929
|
/**
|
|
3056
|
-
* Retrieves the cluster text from a given device.
|
|
3057
|
-
* @param device - The MatterbridgeDevice object.
|
|
3058
|
-
* @returns The attributes of the cluster servers in the device.
|
|
2930
|
+
* Retrieves the cluster text description from a given device.
|
|
2931
|
+
* @param {MatterbridgeDevice} device - The MatterbridgeDevice object.
|
|
2932
|
+
* @returns {string} The attributes description of the cluster servers in the device.
|
|
3059
2933
|
*/
|
|
3060
2934
|
getClusterTextFromDevice(device) {
|
|
3061
2935
|
const stringifyFixedLabel = (endpoint) => {
|
|
@@ -3072,41 +2946,54 @@ export class Matterbridge extends EventEmitter {
|
|
|
3072
2946
|
// this.log.debug(`getClusterTextFromDevice: ${device.name}`);
|
|
3073
2947
|
const clusterServers = device.getAllClusterServers();
|
|
3074
2948
|
clusterServers.forEach((clusterServer) => {
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
|
|
3087
|
-
|
|
3088
|
-
|
|
3089
|
-
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
|
|
2949
|
+
try {
|
|
2950
|
+
// this.log.debug(`***--clusterServer: ${clusterServer.id} (${clusterServer.name})`);
|
|
2951
|
+
if (clusterServer.name === 'OnOff')
|
|
2952
|
+
attributes += `OnOff: ${clusterServer.getOnOffAttribute()} `;
|
|
2953
|
+
if (clusterServer.name === 'Switch')
|
|
2954
|
+
attributes += `Position: ${clusterServer.getCurrentPositionAttribute()} `;
|
|
2955
|
+
if (clusterServer.name === 'WindowCovering')
|
|
2956
|
+
attributes += `Cover position: ${clusterServer.attributes.currentPositionLiftPercent100ths.getLocal() / 100}% `;
|
|
2957
|
+
if (clusterServer.name === 'DoorLock')
|
|
2958
|
+
attributes += `State: ${clusterServer.attributes.lockState.getLocal() === 1 ? 'Locked' : 'Not locked'} `;
|
|
2959
|
+
if (clusterServer.name === 'Thermostat')
|
|
2960
|
+
attributes += `Temperature: ${clusterServer.attributes.localTemperature.getLocal() / 100}°C `;
|
|
2961
|
+
if (clusterServer.name === 'LevelControl')
|
|
2962
|
+
attributes += `Level: ${clusterServer.getCurrentLevelAttribute()}% `;
|
|
2963
|
+
if (clusterServer.name === 'ColorControl' && clusterServer.isAttributeSupportedByName('currentHue'))
|
|
2964
|
+
attributes += `Hue: ${Math.round(clusterServer.getCurrentHueAttribute())} Saturation: ${Math.round(clusterServer.getCurrentSaturationAttribute())}% `;
|
|
2965
|
+
if (clusterServer.name === 'ColorControl' && clusterServer.isAttributeSupportedByName('colorTemperatureMireds'))
|
|
2966
|
+
attributes += `ColorTemp: ${Math.round(clusterServer.getColorTemperatureMiredsAttribute())} `;
|
|
2967
|
+
if (clusterServer.name === 'BooleanState')
|
|
2968
|
+
attributes += `Contact: ${clusterServer.getStateValueAttribute()} `;
|
|
2969
|
+
if (clusterServer.name === 'BooleanStateConfiguration' && clusterServer.isAttributeSupportedByName('alarmsActive'))
|
|
2970
|
+
attributes += `Active alarms: ${stringify(clusterServer.getAlarmsActiveAttribute())} `;
|
|
2971
|
+
if (clusterServer.name === 'FanControl')
|
|
2972
|
+
attributes += `Mode: ${clusterServer.getFanModeAttribute()} Speed: ${clusterServer.getPercentCurrentAttribute()} `;
|
|
2973
|
+
if (clusterServer.name === 'FanControl' && clusterServer.isAttributeSupportedByName('speedCurrent'))
|
|
2974
|
+
attributes += `MultiSpeed: ${clusterServer.getSpeedCurrentAttribute()} `;
|
|
2975
|
+
if (clusterServer.name === 'OccupancySensing')
|
|
2976
|
+
attributes += `Occupancy: ${clusterServer.getOccupancyAttribute().occupied} `;
|
|
2977
|
+
if (clusterServer.name === 'IlluminanceMeasurement')
|
|
2978
|
+
attributes += `Illuminance: ${clusterServer.getMeasuredValueAttribute()} `;
|
|
2979
|
+
if (clusterServer.name === 'AirQuality')
|
|
2980
|
+
attributes += `Air quality: ${clusterServer.getAirQualityAttribute()} `;
|
|
2981
|
+
if (clusterServer.name === 'TvocMeasurement')
|
|
2982
|
+
attributes += `Voc: ${clusterServer.getMeasuredValueAttribute()} `;
|
|
2983
|
+
if (clusterServer.name === 'TemperatureMeasurement')
|
|
2984
|
+
attributes += `Temperature: ${clusterServer.getMeasuredValueAttribute() / 100}°C `;
|
|
2985
|
+
if (clusterServer.name === 'RelativeHumidityMeasurement')
|
|
2986
|
+
attributes += `Humidity: ${clusterServer.getMeasuredValueAttribute() / 100}% `;
|
|
2987
|
+
if (clusterServer.name === 'PressureMeasurement')
|
|
2988
|
+
attributes += `Pressure: ${clusterServer.getMeasuredValueAttribute()} `;
|
|
2989
|
+
if (clusterServer.name === 'FlowMeasurement')
|
|
2990
|
+
attributes += `Flow: ${clusterServer.getMeasuredValueAttribute()} `;
|
|
2991
|
+
if (clusterServer.name === 'FixedLabel')
|
|
2992
|
+
attributes += `${stringifyFixedLabel(device)} `;
|
|
2993
|
+
}
|
|
2994
|
+
catch (error) {
|
|
2995
|
+
this.log.error(`getClusterTextFromDevice with ${clusterServer.name} error: ${error}`);
|
|
2996
|
+
}
|
|
3110
2997
|
});
|
|
3111
2998
|
return attributes;
|
|
3112
2999
|
}
|
|
@@ -3116,14 +3003,13 @@ export class Matterbridge extends EventEmitter {
|
|
|
3116
3003
|
*
|
|
3117
3004
|
* @returns A Promise that resolves when the initialization is complete.
|
|
3118
3005
|
*/
|
|
3119
|
-
async startExtension(dataPath,
|
|
3006
|
+
async startExtension(dataPath, extensionVersion, port = 5540) {
|
|
3120
3007
|
// Set the bridge mode
|
|
3121
3008
|
this.bridgeMode = 'bridge';
|
|
3122
3009
|
// Set the first port to use
|
|
3123
3010
|
this.port = port;
|
|
3124
3011
|
// Set Matterbridge logger
|
|
3125
|
-
this.
|
|
3126
|
-
this.log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logDebug: this.debugEnabled });
|
|
3012
|
+
this.log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: "info" /* LogLevel.INFO */ });
|
|
3127
3013
|
this.log.debug('Matterbridge extension is starting...');
|
|
3128
3014
|
// Initialize NodeStorage
|
|
3129
3015
|
this.matterbridgeDirectory = dataPath;
|
|
@@ -3148,10 +3034,10 @@ export class Matterbridge extends EventEmitter {
|
|
|
3148
3034
|
await this.logNodeAndSystemInfo();
|
|
3149
3035
|
this.matterbridgeDirectory = dataPath;
|
|
3150
3036
|
// Set matter.js logger level and format
|
|
3151
|
-
Logger.defaultLogLevel =
|
|
3037
|
+
Logger.defaultLogLevel = Level.INFO;
|
|
3152
3038
|
Logger.format = Format.ANSI;
|
|
3153
3039
|
// Start the storage and create matterbridgeContext
|
|
3154
|
-
await this.
|
|
3040
|
+
await this.startMatterStorage('json', path.join(this.matterbridgeDirectory, this.matterStorageName));
|
|
3155
3041
|
if (!this.storageManager)
|
|
3156
3042
|
return false;
|
|
3157
3043
|
this.matterbridgeContext = await this.createCommissioningServerContext('Matterbridge', 'Matterbridge zigbee2MQTT', DeviceTypes.AGGREGATOR.code, 0xfff1, 'Matterbridge', 0x8000, 'zigbee2MQTT Matter extension');
|
|
@@ -3195,7 +3081,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
3195
3081
|
// Clearing the session manager
|
|
3196
3082
|
// this.matterbridgeContext?.createContext('SessionManager').clear();
|
|
3197
3083
|
// Closing storage
|
|
3198
|
-
await this.
|
|
3084
|
+
await this.stopMatterStorage();
|
|
3199
3085
|
this.log.info('Matter server stopped');
|
|
3200
3086
|
}
|
|
3201
3087
|
/**
|