matterbridge 1.5.10 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +23 -3
- package/README-SERVICE.md +1 -1
- package/README.md +7 -7
- package/dist/cluster/export.js +1 -1
- package/dist/cluster/export.js.map +1 -1
- package/dist/defaultConfigSchema.d.ts.map +1 -1
- package/dist/defaultConfigSchema.js +9 -1
- package/dist/defaultConfigSchema.js.map +1 -1
- package/dist/matterbridge.d.ts +72 -47
- package/dist/matterbridge.d.ts.map +1 -1
- package/dist/matterbridge.js +144 -118
- package/dist/matterbridge.js.map +1 -1
- package/dist/matterbridgeDevice.d.ts +137 -1029
- package/dist/matterbridgeDevice.d.ts.map +1 -1
- package/dist/matterbridgeDevice.js +55 -361
- package/dist/matterbridgeDevice.js.map +1 -1
- package/dist/matterbridgeEdge.d.ts +90 -0
- package/dist/matterbridgeEdge.d.ts.map +1 -0
- package/dist/matterbridgeEdge.js +555 -0
- package/dist/matterbridgeEdge.js.map +1 -0
- package/dist/matterbridgeEndpoint.d.ts +5195 -0
- package/dist/matterbridgeEndpoint.d.ts.map +1 -0
- package/dist/matterbridgeEndpoint.js +2196 -0
- package/dist/matterbridgeEndpoint.js.map +1 -0
- package/dist/matterbridgeTypes.d.ts +5 -0
- package/dist/matterbridgeTypes.d.ts.map +1 -1
- package/dist/matterbridgeTypes.js.map +1 -1
- package/dist/matterbridgeWebsocket.d.ts +49 -0
- package/dist/matterbridgeWebsocket.d.ts.map +1 -0
- package/dist/matterbridgeWebsocket.js +145 -0
- package/dist/matterbridgeWebsocket.js.map +1 -0
- package/dist/pluginManager.d.ts +134 -1
- package/dist/pluginManager.d.ts.map +1 -1
- package/dist/pluginManager.js +145 -12
- package/dist/pluginManager.js.map +1 -1
- package/frontend/build/asset-manifest.json +3 -3
- package/frontend/build/index.html +1 -1
- package/frontend/build/static/js/{main.96d6324b.js → main.045d08f7.js} +3 -3
- package/frontend/build/static/js/main.045d08f7.js.map +1 -0
- package/npm-shrinkwrap.json +813 -6207
- package/package.json +2 -78
- package/dist/history/export.d.ts +0 -2
- package/dist/history/export.d.ts.map +0 -1
- package/dist/history/export.js +0 -2
- package/dist/history/export.js.map +0 -1
- package/frontend/build/static/js/main.96d6324b.js.map +0 -1
- /package/frontend/build/static/js/{main.96d6324b.js.LICENSE.txt → main.045d08f7.js.LICENSE.txt} +0 -0
package/dist/matterbridge.js
CHANGED
|
@@ -50,6 +50,7 @@ import { StorageBackendDisk, StorageBackendJsonFile, StorageManager } from '@pro
|
|
|
50
50
|
import { getParameter, getIntParameter, hasParameter } from '@project-chip/matter-node.js/util';
|
|
51
51
|
import { CryptoNode } from '@project-chip/matter-node.js/crypto';
|
|
52
52
|
import { Specification } from '@project-chip/matter-node.js/model';
|
|
53
|
+
import { WS_ID_LOG, WS_ID_REFRESH_NEEDED, WS_ID_RESTART_NEEDED, wsMessageHandler } from './matterbridgeWebsocket.js';
|
|
53
54
|
// Default colors
|
|
54
55
|
const plg = '\u001B[38;5;33m';
|
|
55
56
|
const dev = '\u001B[38;5;79m';
|
|
@@ -130,8 +131,6 @@ export class Matterbridge extends EventEmitter {
|
|
|
130
131
|
initialized = false;
|
|
131
132
|
execRunningCount = 0;
|
|
132
133
|
startMatterInterval;
|
|
133
|
-
cleanupTimeout1;
|
|
134
|
-
cleanupTimeout2;
|
|
135
134
|
checkUpdateInterval;
|
|
136
135
|
configureTimeout;
|
|
137
136
|
reachabilityTimeout;
|
|
@@ -160,7 +159,10 @@ export class Matterbridge extends EventEmitter {
|
|
|
160
159
|
// We load asyncronously so is private
|
|
161
160
|
constructor() {
|
|
162
161
|
super();
|
|
162
|
+
// Bind the handler to the instance
|
|
163
|
+
this.matterbridgeMessageHandler = wsMessageHandler.bind(this);
|
|
163
164
|
}
|
|
165
|
+
matterbridgeMessageHandler;
|
|
164
166
|
/** ***********************************************************************************************************************************/
|
|
165
167
|
/** loadInstance() and cleanup() methods */
|
|
166
168
|
/** ***********************************************************************************************************************************/
|
|
@@ -521,8 +523,6 @@ export class Matterbridge extends EventEmitter {
|
|
|
521
523
|
}
|
|
522
524
|
// Start the matter storage and create the matterbridge context
|
|
523
525
|
await this.startMatterStorage('json', path.join(this.matterbridgeDirectory, this.matterStorageName));
|
|
524
|
-
this.log.debug(`Creating commissioning server context for ${plg}Matterbridge${db}`);
|
|
525
|
-
this.matterbridgeContext = await this.createCommissioningServerContext('Matterbridge', 'Matterbridge', DeviceTypes.AGGREGATOR.code, 0xfff1, 'Matterbridge', 0x8000, 'Matterbridge aggregator');
|
|
526
526
|
if (hasParameter('reset') && getParameter('reset') === undefined) {
|
|
527
527
|
this.log.info('Resetting Matterbridge commissioning information...');
|
|
528
528
|
await this.matterbridgeContext?.clearAll();
|
|
@@ -560,12 +560,13 @@ export class Matterbridge extends EventEmitter {
|
|
|
560
560
|
this.getPluginLatestVersion(plugin);
|
|
561
561
|
}
|
|
562
562
|
}, 60 * 60 * 1000);
|
|
563
|
+
// Start the matterbridge in mode test
|
|
563
564
|
if (hasParameter('test')) {
|
|
564
565
|
this.bridgeMode = 'bridge';
|
|
565
566
|
MatterbridgeDevice.bridgeMode = 'bridge';
|
|
566
|
-
await this.startTest();
|
|
567
567
|
return;
|
|
568
568
|
}
|
|
569
|
+
// Start the matterbridge in mode controller
|
|
569
570
|
if (hasParameter('controller')) {
|
|
570
571
|
this.bridgeMode = 'controller';
|
|
571
572
|
await this.startController();
|
|
@@ -576,91 +577,63 @@ export class Matterbridge extends EventEmitter {
|
|
|
576
577
|
this.log.info('Setting default matterbridge start mode to bridge');
|
|
577
578
|
await this.nodeContext?.set('bridgeMode', 'bridge');
|
|
578
579
|
}
|
|
580
|
+
// Start matterbridge in bridge mode
|
|
579
581
|
if (hasParameter('bridge') || (!hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'bridge')) {
|
|
580
582
|
this.bridgeMode = 'bridge';
|
|
581
583
|
MatterbridgeDevice.bridgeMode = 'bridge';
|
|
582
|
-
|
|
583
|
-
throw new Error('No storage manager initialized');
|
|
584
|
-
this.log.debug('Starting matterbridge in mode', this.bridgeMode);
|
|
585
|
-
this.matterServer = this.createMatterServer(this.storageManager);
|
|
586
|
-
this.log.debug(`Creating commissioning server for ${plg}Matterbridge${db}`);
|
|
587
|
-
this.commissioningServer = await this.createCommisioningServer(this.matterbridgeContext, 'Matterbridge');
|
|
588
|
-
this.log.debug(`Creating matter aggregator for ${plg}Matterbridge${db}`);
|
|
589
|
-
this.matterAggregator = await this.createMatterAggregator(this.matterbridgeContext, 'Matterbridge');
|
|
590
|
-
this.log.debug('Adding matterbridge aggregator to commissioning server');
|
|
591
|
-
this.commissioningServer.addDevice(this.matterAggregator);
|
|
592
|
-
this.log.debug('Adding matterbridge commissioning server to matter server');
|
|
593
|
-
await this.matterServer.addCommissioningServer(this.commissioningServer, { uniqueStorageKey: 'Matterbridge' });
|
|
594
|
-
for (const plugin of this.plugins) {
|
|
595
|
-
plugin.configJson = await this.plugins.loadConfig(plugin);
|
|
596
|
-
plugin.schemaJson = await this.plugins.loadSchema(plugin);
|
|
597
|
-
// Check if the plugin is available
|
|
598
|
-
if (!(await this.plugins.resolve(plugin.path))) {
|
|
599
|
-
this.log.error(`Plugin ${plg}${plugin.name}${er} not found or not validated. Disabling it.`);
|
|
600
|
-
plugin.enabled = false;
|
|
601
|
-
plugin.error = true;
|
|
602
|
-
continue;
|
|
603
|
-
}
|
|
604
|
-
// Check if the plugin has a new version
|
|
605
|
-
this.getPluginLatestVersion(plugin); // No await do it asyncronously
|
|
606
|
-
if (!plugin.enabled) {
|
|
607
|
-
this.log.info(`Plugin ${plg}${plugin.name}${nf} not enabled`);
|
|
608
|
-
continue;
|
|
609
|
-
}
|
|
610
|
-
plugin.error = false;
|
|
611
|
-
plugin.locked = false;
|
|
612
|
-
plugin.loaded = false;
|
|
613
|
-
plugin.started = false;
|
|
614
|
-
plugin.configured = false;
|
|
615
|
-
plugin.connected = undefined;
|
|
616
|
-
plugin.registeredDevices = undefined;
|
|
617
|
-
plugin.addedDevices = undefined;
|
|
618
|
-
plugin.qrPairingCode = undefined;
|
|
619
|
-
plugin.manualPairingCode = undefined;
|
|
620
|
-
this.plugins.load(plugin, true, 'Matterbridge is starting'); // No await do it asyncronously
|
|
621
|
-
}
|
|
584
|
+
this.log.debug(`Starting matterbridge in mode ${this.bridgeMode}`);
|
|
622
585
|
await this.startBridge();
|
|
623
586
|
return;
|
|
624
587
|
}
|
|
588
|
+
// Start matterbridge in childbridge mode
|
|
625
589
|
if (hasParameter('childbridge') || (!hasParameter('bridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'childbridge')) {
|
|
626
590
|
this.bridgeMode = 'childbridge';
|
|
627
591
|
MatterbridgeDevice.bridgeMode = 'childbridge';
|
|
628
|
-
|
|
629
|
-
throw new Error('No storage manager initialized');
|
|
630
|
-
this.log.debug('Starting matterbridge in mode', this.bridgeMode);
|
|
631
|
-
this.matterServer = this.createMatterServer(this.storageManager);
|
|
632
|
-
for (const plugin of this.plugins) {
|
|
633
|
-
plugin.configJson = await this.plugins.loadConfig(plugin);
|
|
634
|
-
plugin.schemaJson = await this.plugins.loadSchema(plugin);
|
|
635
|
-
// Check if the plugin is available
|
|
636
|
-
if (!(await this.plugins.resolve(plugin.path))) {
|
|
637
|
-
this.log.error(`Plugin ${plg}${plugin.name}${er} not found or not validated. Disabling it.`);
|
|
638
|
-
plugin.enabled = false;
|
|
639
|
-
plugin.error = true;
|
|
640
|
-
continue;
|
|
641
|
-
}
|
|
642
|
-
// Check if the plugin has a new version
|
|
643
|
-
this.getPluginLatestVersion(plugin); // No await do it asyncronously
|
|
644
|
-
if (!plugin.enabled) {
|
|
645
|
-
this.log.info(`Plugin ${plg}${plugin.name}${nf} not enabled`);
|
|
646
|
-
continue;
|
|
647
|
-
}
|
|
648
|
-
plugin.error = false;
|
|
649
|
-
plugin.locked = false;
|
|
650
|
-
plugin.loaded = false;
|
|
651
|
-
plugin.started = false;
|
|
652
|
-
plugin.configured = false;
|
|
653
|
-
plugin.connected = false;
|
|
654
|
-
plugin.registeredDevices = undefined;
|
|
655
|
-
plugin.addedDevices = undefined;
|
|
656
|
-
plugin.qrPairingCode = undefined;
|
|
657
|
-
plugin.manualPairingCode = undefined;
|
|
658
|
-
this.plugins.load(plugin, true, 'Matterbridge is starting'); // No await do it asyncronously
|
|
659
|
-
}
|
|
592
|
+
this.log.debug(`Starting matterbridge in mode ${this.bridgeMode}`);
|
|
660
593
|
await this.startChildbridge();
|
|
661
594
|
return;
|
|
662
595
|
}
|
|
663
596
|
}
|
|
597
|
+
/**
|
|
598
|
+
* Asynchronously loads and starts the registered plugins.
|
|
599
|
+
*
|
|
600
|
+
* This method is responsible for initializing and staarting all enabled plugins.
|
|
601
|
+
* It ensures that each plugin is properly loaded and started before the ridge starts.
|
|
602
|
+
*
|
|
603
|
+
* @returns {Promise<void>} A promise that resolves when all plugins have been loaded and started.
|
|
604
|
+
*/
|
|
605
|
+
async startPlugins() {
|
|
606
|
+
// Check, load and start the plugins
|
|
607
|
+
for (const plugin of this.plugins) {
|
|
608
|
+
plugin.configJson = await this.plugins.loadConfig(plugin);
|
|
609
|
+
plugin.schemaJson = await this.plugins.loadSchema(plugin);
|
|
610
|
+
// Check if the plugin is available
|
|
611
|
+
if (!(await this.plugins.resolve(plugin.path))) {
|
|
612
|
+
this.log.error(`Plugin ${plg}${plugin.name}${er} not found or not validated. Disabling it.`);
|
|
613
|
+
plugin.enabled = false;
|
|
614
|
+
plugin.error = true;
|
|
615
|
+
continue;
|
|
616
|
+
}
|
|
617
|
+
// Check if the plugin has a new version
|
|
618
|
+
this.getPluginLatestVersion(plugin); // No await do it asyncronously
|
|
619
|
+
if (!plugin.enabled) {
|
|
620
|
+
this.log.info(`Plugin ${plg}${plugin.name}${nf} not enabled`);
|
|
621
|
+
continue;
|
|
622
|
+
}
|
|
623
|
+
plugin.error = false;
|
|
624
|
+
plugin.locked = false;
|
|
625
|
+
plugin.loaded = false;
|
|
626
|
+
plugin.started = false;
|
|
627
|
+
plugin.configured = false;
|
|
628
|
+
plugin.connected = undefined;
|
|
629
|
+
plugin.registeredDevices = undefined;
|
|
630
|
+
plugin.addedDevices = undefined;
|
|
631
|
+
plugin.qrPairingCode = undefined;
|
|
632
|
+
plugin.manualPairingCode = undefined;
|
|
633
|
+
this.plugins.load(plugin, true, 'Matterbridge is starting'); // No await do it asyncronously
|
|
634
|
+
}
|
|
635
|
+
this.wssSendRefreshRequired();
|
|
636
|
+
}
|
|
664
637
|
/**
|
|
665
638
|
* Registers the signal handlers for SIGINT and SIGTERM.
|
|
666
639
|
* When either of these signals are received, the cleanup method is called with an appropriate message.
|
|
@@ -1155,7 +1128,6 @@ export class Matterbridge extends EventEmitter {
|
|
|
1155
1128
|
});
|
|
1156
1129
|
this.webSocketServer = undefined;
|
|
1157
1130
|
}
|
|
1158
|
-
// this.cleanupTimeout1 = setTimeout(async () => {
|
|
1159
1131
|
// Closing matter
|
|
1160
1132
|
await this.stopMatterServer();
|
|
1161
1133
|
// Closing matter storage
|
|
@@ -1201,9 +1173,6 @@ export class Matterbridge extends EventEmitter {
|
|
|
1201
1173
|
}
|
|
1202
1174
|
this.plugins.clear();
|
|
1203
1175
|
this.devices.clear();
|
|
1204
|
-
// this.registeredDevices = [];
|
|
1205
|
-
// this.log.info('Waiting for matter to deliver last messages...');
|
|
1206
|
-
// this.cleanupTimeout2 = setTimeout(async () => {
|
|
1207
1176
|
if (restart) {
|
|
1208
1177
|
if (message === 'updating...') {
|
|
1209
1178
|
this.log.info('Cleanup completed. Updating...');
|
|
@@ -1238,8 +1207,6 @@ export class Matterbridge extends EventEmitter {
|
|
|
1238
1207
|
}
|
|
1239
1208
|
this.hasCleanupStarted = false;
|
|
1240
1209
|
this.initialized = false;
|
|
1241
|
-
// }, 2 * 1000);
|
|
1242
|
-
// }, 3 * 1000);
|
|
1243
1210
|
}
|
|
1244
1211
|
}
|
|
1245
1212
|
/**
|
|
@@ -1249,17 +1216,17 @@ export class Matterbridge extends EventEmitter {
|
|
|
1249
1216
|
* @returns {Promise<void>} - A promise that resolves when the device is added.
|
|
1250
1217
|
*/
|
|
1251
1218
|
async addBridgedDevice(pluginName, device) {
|
|
1252
|
-
this.log.debug(`Adding bridged device ${dev}${device.deviceName}${db} (${
|
|
1219
|
+
this.log.debug(`Adding bridged device ${dev}${device.deviceName}${db} (${zb}${device.name}${db}) for plugin ${plg}${pluginName}${db}`);
|
|
1253
1220
|
// Check if the plugin is registered
|
|
1254
1221
|
const plugin = this.plugins.get(pluginName);
|
|
1255
1222
|
if (!plugin) {
|
|
1256
|
-
this.log.error(`Error adding bridged device ${dev}${device.deviceName}${er} (${
|
|
1223
|
+
this.log.error(`Error adding bridged device ${dev}${device.deviceName}${er} (${zb}${device.name}${er}) plugin ${plg}${pluginName}${er} not found`);
|
|
1257
1224
|
return;
|
|
1258
1225
|
}
|
|
1259
1226
|
// Register and add the device to matterbridge aggregator in bridge mode
|
|
1260
1227
|
if (this.bridgeMode === 'bridge') {
|
|
1261
1228
|
if (!this.matterAggregator) {
|
|
1262
|
-
this.log.error(`Adding bridged device ${dev}${device.deviceName}${er} (${
|
|
1229
|
+
this.log.error(`Adding bridged device ${dev}${device.deviceName}${er} (${zb}${device.name}${er}) for plugin ${plg}${pluginName}${er} error: matterAggregator not found`);
|
|
1263
1230
|
return;
|
|
1264
1231
|
}
|
|
1265
1232
|
this.matterAggregator.addBridgedDevice(device);
|
|
@@ -1314,17 +1281,17 @@ export class Matterbridge extends EventEmitter {
|
|
|
1314
1281
|
* @returns A Promise that resolves when the device is successfully removed.
|
|
1315
1282
|
*/
|
|
1316
1283
|
async removeBridgedDevice(pluginName, device) {
|
|
1317
|
-
this.log.debug(`Removing bridged device ${dev}${device.deviceName}${db} (${
|
|
1284
|
+
this.log.debug(`Removing bridged device ${dev}${device.deviceName}${db} (${zb}${device.name}${db}) for plugin ${plg}${pluginName}${db}`);
|
|
1318
1285
|
// Check if the plugin is registered
|
|
1319
1286
|
const plugin = this.plugins.get(pluginName);
|
|
1320
1287
|
if (!plugin) {
|
|
1321
|
-
this.log.error(`Error removing bridged device ${dev}${device.deviceName}${er} (${
|
|
1288
|
+
this.log.error(`Error removing bridged device ${dev}${device.deviceName}${er} (${zb}${device.name}${er}) for plugin ${plg}${pluginName}${er}: plugin not found`);
|
|
1322
1289
|
return;
|
|
1323
1290
|
}
|
|
1324
1291
|
// Remove the device from matterbridge aggregator in bridge mode
|
|
1325
1292
|
if (this.bridgeMode === 'bridge') {
|
|
1326
1293
|
if (!this.matterAggregator) {
|
|
1327
|
-
this.log.error(`Error removing bridged device ${dev}${device.deviceName}${er} (${
|
|
1294
|
+
this.log.error(`Error removing bridged device ${dev}${device.deviceName}${er} (${zb}${device.name}${er}) for plugin ${plg}${pluginName}${er}: matterAggregator not found`);
|
|
1328
1295
|
return;
|
|
1329
1296
|
}
|
|
1330
1297
|
if (device.number !== undefined) {
|
|
@@ -1334,7 +1301,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
1334
1301
|
// device.getClusterServerById(BridgedDeviceBasicInformation.Cluster.id)?.triggerShutDownEvent({});
|
|
1335
1302
|
// device.getClusterServerById(BridgedDeviceBasicInformation.Cluster.id)?.triggerLeaveEvent({});
|
|
1336
1303
|
this.matterAggregator?.removeBridgedDevice(device);
|
|
1337
|
-
this.log.info(`Removed bridged device(${plugin.registeredDevices}/${plugin.addedDevices}) ${dev}${device.deviceName}${nf} (${
|
|
1304
|
+
this.log.info(`Removed bridged device(${plugin.registeredDevices}/${plugin.addedDevices}) ${dev}${device.deviceName}${nf} (${zb}${device.name}${nf}) for plugin ${plg}${pluginName}${nf}`);
|
|
1338
1305
|
if (plugin.registeredDevices !== undefined)
|
|
1339
1306
|
plugin.registeredDevices--;
|
|
1340
1307
|
if (plugin.addedDevices !== undefined)
|
|
@@ -1344,13 +1311,13 @@ export class Matterbridge extends EventEmitter {
|
|
|
1344
1311
|
if (this.bridgeMode === 'childbridge') {
|
|
1345
1312
|
if (plugin.type === 'AccessoryPlatform') {
|
|
1346
1313
|
if (!plugin.commissioningServer) {
|
|
1347
|
-
this.log.error(`Error removing bridged device ${dev}${device.deviceName}${er} (${
|
|
1314
|
+
this.log.error(`Error removing bridged device ${dev}${device.deviceName}${er} (${zb}${device.name}${er}) for plugin ${plg}${pluginName}${er}: commissioning server not found`);
|
|
1348
1315
|
return;
|
|
1349
1316
|
}
|
|
1350
1317
|
}
|
|
1351
1318
|
else if (plugin.type === 'DynamicPlatform') {
|
|
1352
1319
|
if (!plugin.aggregator) {
|
|
1353
|
-
this.log.error(`Error removing bridged device ${dev}${device.deviceName}${er} (${
|
|
1320
|
+
this.log.error(`Error removing bridged device ${dev}${device.deviceName}${er} (${zb}${device.name}${er}) for plugin ${plg}${pluginName}${er}: aggregator not found`);
|
|
1354
1321
|
return;
|
|
1355
1322
|
}
|
|
1356
1323
|
if (device.number !== undefined) {
|
|
@@ -1359,7 +1326,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
1359
1326
|
}
|
|
1360
1327
|
plugin.aggregator.removeBridgedDevice(device);
|
|
1361
1328
|
}
|
|
1362
|
-
this.log.info(`Removed bridged device(${plugin.registeredDevices}/${plugin.addedDevices}) ${dev}${device.deviceName}${nf} (${
|
|
1329
|
+
this.log.info(`Removed bridged device(${plugin.registeredDevices}/${plugin.addedDevices}) ${dev}${device.deviceName}${nf} (${zb}${device.name}${nf}) for plugin ${plg}${pluginName}${nf}`);
|
|
1363
1330
|
if (plugin.registeredDevices !== undefined)
|
|
1364
1331
|
plugin.registeredDevices--;
|
|
1365
1332
|
if (plugin.addedDevices !== undefined)
|
|
@@ -1388,18 +1355,28 @@ export class Matterbridge extends EventEmitter {
|
|
|
1388
1355
|
}
|
|
1389
1356
|
});
|
|
1390
1357
|
}
|
|
1391
|
-
async startTest() {
|
|
1392
|
-
// Start the Matterbridge test
|
|
1393
|
-
}
|
|
1394
1358
|
/**
|
|
1395
1359
|
* Starts the Matterbridge in bridge mode.
|
|
1396
1360
|
* @private
|
|
1397
1361
|
* @returns {Promise<void>} A promise that resolves when the Matterbridge is started.
|
|
1398
1362
|
*/
|
|
1399
1363
|
async startBridge() {
|
|
1400
|
-
// Plugins are loaded and started by loadPlugin on startup and plugin.loaded and plugin.started are set to true
|
|
1401
1364
|
// Plugins are configured by a timer when matter server is started and plugin.configured is set to true
|
|
1402
|
-
this.
|
|
1365
|
+
if (!this.storageManager)
|
|
1366
|
+
throw new Error('No storage manager initialized');
|
|
1367
|
+
if (!this.matterbridgeContext)
|
|
1368
|
+
throw new Error('No storage context initialized');
|
|
1369
|
+
this.matterServer = this.createMatterServer(this.storageManager);
|
|
1370
|
+
this.log.debug(`Creating commissioning server for ${plg}Matterbridge${db}`);
|
|
1371
|
+
this.commissioningServer = await this.createCommisioningServer(this.matterbridgeContext, 'Matterbridge');
|
|
1372
|
+
this.log.debug(`Creating matter aggregator for ${plg}Matterbridge${db}`);
|
|
1373
|
+
this.matterAggregator = await this.createMatterAggregator(this.matterbridgeContext, 'Matterbridge');
|
|
1374
|
+
this.log.debug('Adding matterbridge aggregator to commissioning server');
|
|
1375
|
+
this.commissioningServer.addDevice(this.matterAggregator);
|
|
1376
|
+
this.log.debug('Adding matterbridge commissioning server to matter server');
|
|
1377
|
+
await this.matterServer.addCommissioningServer(this.commissioningServer, { uniqueStorageKey: 'Matterbridge' });
|
|
1378
|
+
await this.startPlugins();
|
|
1379
|
+
this.log.debug('Starting start matter interval in bridge mode');
|
|
1403
1380
|
let failCount = 0;
|
|
1404
1381
|
this.startMatterInterval = setInterval(async () => {
|
|
1405
1382
|
for (const plugin of this.plugins) {
|
|
@@ -1428,8 +1405,11 @@ export class Matterbridge extends EventEmitter {
|
|
|
1428
1405
|
clearInterval(this.startMatterInterval);
|
|
1429
1406
|
this.startMatterInterval = undefined;
|
|
1430
1407
|
this.log.debug('Cleared startMatterInterval interval for Matterbridge');
|
|
1408
|
+
// Start the Matter server
|
|
1431
1409
|
await this.startMatterServer();
|
|
1432
1410
|
this.log.notice('Matter server started');
|
|
1411
|
+
// Show the QR code for commissioning or log the already commissioned message
|
|
1412
|
+
await this.showCommissioningQRCode(this.commissioningServer, this.matterbridgeContext, this.nodeContext, 'Matterbridge');
|
|
1433
1413
|
// Configure the plugins
|
|
1434
1414
|
this.configureTimeout = setTimeout(async () => {
|
|
1435
1415
|
for (const plugin of this.plugins) {
|
|
@@ -1443,9 +1423,8 @@ export class Matterbridge extends EventEmitter {
|
|
|
1443
1423
|
this.log.error(`Error configuring plugin ${plg}${plugin.name}${er}`, error);
|
|
1444
1424
|
}
|
|
1445
1425
|
}
|
|
1426
|
+
this.wssSendRefreshRequired();
|
|
1446
1427
|
}, 30 * 1000);
|
|
1447
|
-
// Show the QR code for commissioning or log the already commissioned message
|
|
1448
|
-
await this.showCommissioningQRCode(this.commissioningServer, this.matterbridgeContext, this.nodeContext, 'Matterbridge');
|
|
1449
1428
|
// Setting reachability to true
|
|
1450
1429
|
this.reachabilityTimeout = setTimeout(() => {
|
|
1451
1430
|
this.log.info(`Setting reachability to true for ${plg}Matterbridge${db}`);
|
|
@@ -1462,9 +1441,12 @@ export class Matterbridge extends EventEmitter {
|
|
|
1462
1441
|
* @returns {Promise<void>} A promise that resolves when the Matterbridge is started.
|
|
1463
1442
|
*/
|
|
1464
1443
|
async startChildbridge() {
|
|
1465
|
-
//
|
|
1466
|
-
// addDevice and addBridgedDeevice create the commissionig servers and add the devices to the the commissioning server or to the aggregator
|
|
1444
|
+
// Matterbridge.addBridgedDevice creates the commissionig servers and add the devices to the the commissioning server or to the aggregator
|
|
1467
1445
|
// Plugins are configured by a timer when matter server is started and plugin.configured is set to true
|
|
1446
|
+
if (!this.storageManager)
|
|
1447
|
+
throw new Error('No storage manager initialized');
|
|
1448
|
+
this.matterServer = this.createMatterServer(this.storageManager);
|
|
1449
|
+
await this.startPlugins();
|
|
1468
1450
|
this.log.debug('Starting start matter interval in childbridge mode...');
|
|
1469
1451
|
let failCount = 0;
|
|
1470
1452
|
this.startMatterInterval = setInterval(async () => {
|
|
@@ -1476,7 +1458,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
1476
1458
|
if (plugin.error) {
|
|
1477
1459
|
clearInterval(this.startMatterInterval);
|
|
1478
1460
|
this.startMatterInterval = undefined;
|
|
1479
|
-
this.log.debug('Cleared startMatterInterval interval for
|
|
1461
|
+
this.log.debug('Cleared startMatterInterval interval for a plugin in error state');
|
|
1480
1462
|
this.log.error(`The plugin ${plg}${plugin.name}${er} is in error state.`);
|
|
1481
1463
|
this.log.error('The bridge will not start until the problem is solved to prevent the controllers from deleting all registered devices.');
|
|
1482
1464
|
this.log.error('If you want to start the bridge disable the plugin in error state and restart.');
|
|
@@ -1498,6 +1480,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
1498
1480
|
clearInterval(this.startMatterInterval);
|
|
1499
1481
|
this.startMatterInterval = undefined;
|
|
1500
1482
|
this.log.debug('Cleared startMatterInterval interval in childbridge mode');
|
|
1483
|
+
// Start the Matter server
|
|
1501
1484
|
await this.startMatterServer();
|
|
1502
1485
|
this.log.notice('Matter server started');
|
|
1503
1486
|
// Configure the plugins
|
|
@@ -1513,6 +1496,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
1513
1496
|
this.log.error(`Error configuring plugin ${plg}${plugin.name}${er}`, error);
|
|
1514
1497
|
}
|
|
1515
1498
|
}
|
|
1499
|
+
this.wssSendRefreshRequired();
|
|
1516
1500
|
}, 30 * 1000);
|
|
1517
1501
|
for (const plugin of this.plugins) {
|
|
1518
1502
|
if (!plugin.enabled || plugin.error)
|
|
@@ -1753,7 +1737,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
1753
1737
|
await this.storageManager.initialize();
|
|
1754
1738
|
this.log.debug('Storage initialized');
|
|
1755
1739
|
if (storageType === 'json') {
|
|
1756
|
-
await this.
|
|
1740
|
+
await this.backupMatterStorage(storageName, storageName.replace('.json', '') + '.backup.json');
|
|
1757
1741
|
}
|
|
1758
1742
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1759
1743
|
}
|
|
@@ -1762,6 +1746,8 @@ export class Matterbridge extends EventEmitter {
|
|
|
1762
1746
|
this.log.error(`Please delete it and rename ${storageName.replace('.json', '.backup.json')} to ${storageName} and try to restart Matterbridge.`);
|
|
1763
1747
|
await this.cleanup('Storage initialize() error!');
|
|
1764
1748
|
}
|
|
1749
|
+
this.log.debug(`Creating commissioning server context for ${plg}Matterbridge${db}`);
|
|
1750
|
+
this.matterbridgeContext = await this.createCommissioningServerContext('Matterbridge', 'Matterbridge', DeviceTypes.AGGREGATOR.code, 0xfff1, 'Matterbridge', 0x8000, 'Matterbridge aggregator');
|
|
1765
1751
|
}
|
|
1766
1752
|
/**
|
|
1767
1753
|
* Makes a backup copy of the specified matter JSON storage file.
|
|
@@ -1769,7 +1755,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
1769
1755
|
* @param storageName - The name of the JSON storage file to be backed up.
|
|
1770
1756
|
* @param backupName - The name of the backup file to be created.
|
|
1771
1757
|
*/
|
|
1772
|
-
async
|
|
1758
|
+
async backupMatterStorage(storageName, backupName) {
|
|
1773
1759
|
try {
|
|
1774
1760
|
this.log.debug(`Making backup copy of ${storageName}`);
|
|
1775
1761
|
await fs.copyFile(storageName, backupName);
|
|
@@ -2010,6 +1996,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
2010
1996
|
}
|
|
2011
1997
|
}
|
|
2012
1998
|
}
|
|
1999
|
+
this.wssSendRefreshRequired();
|
|
2013
2000
|
},
|
|
2014
2001
|
commissioningChangedCallback: async (fabricIndex) => {
|
|
2015
2002
|
const fabricInfo = commissioningServer.getCommissionedFabricInformation(fabricIndex);
|
|
@@ -2052,6 +2039,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
2052
2039
|
}
|
|
2053
2040
|
}
|
|
2054
2041
|
}
|
|
2042
|
+
this.wssSendRefreshRequired();
|
|
2055
2043
|
},
|
|
2056
2044
|
});
|
|
2057
2045
|
if (this.passcode !== undefined)
|
|
@@ -2211,6 +2199,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
2211
2199
|
}
|
|
2212
2200
|
}
|
|
2213
2201
|
}
|
|
2202
|
+
this.wssSendRefreshRequired();
|
|
2214
2203
|
}
|
|
2215
2204
|
/**
|
|
2216
2205
|
* Sanitizes the fabric information by converting bigint properties to string cause res.json doesn't know bigint.
|
|
@@ -2333,6 +2322,9 @@ export class Matterbridge extends EventEmitter {
|
|
|
2333
2322
|
case 4701:
|
|
2334
2323
|
vendorName = '(Tuya)';
|
|
2335
2324
|
break;
|
|
2325
|
+
case 4718:
|
|
2326
|
+
vendorName = '(Xiaomi)';
|
|
2327
|
+
break;
|
|
2336
2328
|
case 4742:
|
|
2337
2329
|
vendorName = '(eWeLink)';
|
|
2338
2330
|
break;
|
|
@@ -2508,7 +2500,33 @@ export class Matterbridge extends EventEmitter {
|
|
|
2508
2500
|
// Send the message to all connected clients
|
|
2509
2501
|
this.webSocketServer?.clients.forEach((client) => {
|
|
2510
2502
|
if (client.readyState === WebSocket.OPEN) {
|
|
2511
|
-
client.send(JSON.stringify({ level, time, name, message }));
|
|
2503
|
+
client.send(JSON.stringify({ id: WS_ID_LOG, src: 'Matterbridge', level, time, name, message }));
|
|
2504
|
+
}
|
|
2505
|
+
});
|
|
2506
|
+
}
|
|
2507
|
+
/**
|
|
2508
|
+
* Sends a need to refresh WebSocket message to all connected clients.
|
|
2509
|
+
*
|
|
2510
|
+
*/
|
|
2511
|
+
wssSendRefreshRequired() {
|
|
2512
|
+
this.matterbridgeInformation.refreshRequired = true;
|
|
2513
|
+
// Send the message to all connected clients
|
|
2514
|
+
this.webSocketServer?.clients.forEach((client) => {
|
|
2515
|
+
if (client.readyState === WebSocket.OPEN) {
|
|
2516
|
+
client.send(JSON.stringify({ id: WS_ID_REFRESH_NEEDED, src: 'Matterbridge', dst: 'Matterbridge', method: 'refresh_required', params: {} }));
|
|
2517
|
+
}
|
|
2518
|
+
});
|
|
2519
|
+
}
|
|
2520
|
+
/**
|
|
2521
|
+
* Sends a need to restart WebSocket message to all connected clients.
|
|
2522
|
+
*
|
|
2523
|
+
*/
|
|
2524
|
+
wssSendRestartRequired() {
|
|
2525
|
+
this.matterbridgeInformation.restartRequired = true;
|
|
2526
|
+
// Send the message to all connected clients
|
|
2527
|
+
this.webSocketServer?.clients.forEach((client) => {
|
|
2528
|
+
if (client.readyState === WebSocket.OPEN) {
|
|
2529
|
+
client.send(JSON.stringify({ id: WS_ID_RESTART_NEEDED, src: 'Matterbridge', dst: 'Matterbridge', method: 'restart_required', params: {} }));
|
|
2512
2530
|
}
|
|
2513
2531
|
});
|
|
2514
2532
|
}
|
|
@@ -2627,7 +2645,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
2627
2645
|
}
|
|
2628
2646
|
if (initializeError)
|
|
2629
2647
|
return;
|
|
2630
|
-
// Createe a WebSocket server and attach it to the http server
|
|
2648
|
+
// Createe a WebSocket server and attach it to the http or https server
|
|
2631
2649
|
const wssPort = port;
|
|
2632
2650
|
const wssHost = hasParameter('ssl') ? `wss://${this.systemInformation.ipv4Address}:${wssPort}` : `ws://${this.systemInformation.ipv4Address}:${wssPort}`;
|
|
2633
2651
|
this.webSocketServer = new WebSocketServer(hasParameter('ssl') ? { server: this.httpsServer } : { server: this.httpServer });
|
|
@@ -2637,6 +2655,14 @@ export class Matterbridge extends EventEmitter {
|
|
|
2637
2655
|
this.log.info(`WebSocketServer client "${clientIp}" connected to Matterbridge`);
|
|
2638
2656
|
ws.on('message', (message) => {
|
|
2639
2657
|
this.log.debug(`WebSocket client message: ${message}`);
|
|
2658
|
+
this.matterbridgeMessageHandler(ws, message);
|
|
2659
|
+
});
|
|
2660
|
+
ws.on('ping', () => {
|
|
2661
|
+
this.log.debug('WebSocket client ping');
|
|
2662
|
+
ws.pong();
|
|
2663
|
+
});
|
|
2664
|
+
ws.on('pong', () => {
|
|
2665
|
+
this.log.debug('WebSocket client pong');
|
|
2640
2666
|
});
|
|
2641
2667
|
ws.on('close', () => {
|
|
2642
2668
|
this.log.info('WebSocket client disconnected');
|
|
@@ -2699,12 +2725,8 @@ export class Matterbridge extends EventEmitter {
|
|
|
2699
2725
|
this.matterbridgeInformation.matterbridgeQrPairingCode = this.matterbridgeQrPairingCode;
|
|
2700
2726
|
this.matterbridgeInformation.matterbridgeManualPairingCode = this.matterbridgeManualPairingCode;
|
|
2701
2727
|
this.matterbridgeInformation.matterbridgeFabricInformations = this.matterbridgeFabricInformations;
|
|
2702
|
-
// this.matterbridgeInformation.matterbridgeSessionInformations = this.matterbridgeSessionInformations;
|
|
2703
2728
|
this.matterbridgeInformation.matterbridgeSessionInformations = Array.from(this.matterbridgeSessionInformations.values());
|
|
2704
|
-
|
|
2705
|
-
if (this.profile)
|
|
2706
|
-
this.matterbridgeInformation.profile = this.profile;
|
|
2707
|
-
// const response = { wssHost, ssl: hasParameter('ssl'), qrPairingCode, manualPairingCode, systemInformation: this.systemInformation, matterbridgeInformation: this.matterbridgeInformation };
|
|
2729
|
+
this.matterbridgeInformation.profile = this.profile;
|
|
2708
2730
|
const response = { wssHost, ssl: hasParameter('ssl'), systemInformation: this.systemInformation, matterbridgeInformation: this.matterbridgeInformation };
|
|
2709
2731
|
// this.log.debug('Response:', debugStringify(response));
|
|
2710
2732
|
res.json(response);
|
|
@@ -2785,7 +2807,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
2785
2807
|
});
|
|
2786
2808
|
});
|
|
2787
2809
|
device.getChildEndpoints().forEach((childEndpoint) => {
|
|
2788
|
-
const name =
|
|
2810
|
+
const name = childEndpoint.uniqueStorageKey;
|
|
2789
2811
|
const clusterServers = childEndpoint.getAllClusterServers();
|
|
2790
2812
|
clusterServers.forEach((clusterServer) => {
|
|
2791
2813
|
Object.entries(clusterServer.attributes).forEach(([key, value]) => {
|
|
@@ -2819,7 +2841,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
2819
2841
|
});
|
|
2820
2842
|
res.json(data);
|
|
2821
2843
|
});
|
|
2822
|
-
// Endpoint to
|
|
2844
|
+
// Endpoint to view the log
|
|
2823
2845
|
this.expressApp.get('/api/view-log', async (req, res) => {
|
|
2824
2846
|
this.log.debug('The frontend sent /api/log');
|
|
2825
2847
|
try {
|
|
@@ -2941,7 +2963,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
2941
2963
|
// Handle the command setbridgemode from Settings
|
|
2942
2964
|
if (command === 'setbridgemode') {
|
|
2943
2965
|
this.log.debug(`setbridgemode: ${param}`);
|
|
2944
|
-
this.
|
|
2966
|
+
this.wssSendRestartRequired();
|
|
2945
2967
|
await this.nodeContext?.set('bridgeMode', param);
|
|
2946
2968
|
res.json({ message: 'Command received' });
|
|
2947
2969
|
return;
|
|
@@ -3121,7 +3143,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
3121
3143
|
this.log.error('Error updating matterbridge');
|
|
3122
3144
|
}
|
|
3123
3145
|
await this.updateProcess();
|
|
3124
|
-
this.
|
|
3146
|
+
this.wssSendRestartRequired();
|
|
3125
3147
|
res.json({ message: 'Command received' });
|
|
3126
3148
|
return;
|
|
3127
3149
|
}
|
|
@@ -3139,7 +3161,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
3139
3161
|
return;
|
|
3140
3162
|
this.plugins.saveConfigFromJson(plugin, req.body);
|
|
3141
3163
|
}
|
|
3142
|
-
this.
|
|
3164
|
+
this.wssSendRestartRequired();
|
|
3143
3165
|
res.json({ message: 'Command received' });
|
|
3144
3166
|
return;
|
|
3145
3167
|
}
|
|
@@ -3155,7 +3177,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
3155
3177
|
catch (error) {
|
|
3156
3178
|
this.log.error(`Error installing plugin ${plg}${param}${er}`);
|
|
3157
3179
|
}
|
|
3158
|
-
this.
|
|
3180
|
+
this.wssSendRestartRequired();
|
|
3159
3181
|
// Also add the plugin to matterbridge so no return!
|
|
3160
3182
|
// res.json({ message: 'Command received' });
|
|
3161
3183
|
// return;
|
|
@@ -3168,6 +3190,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
3168
3190
|
this.plugins.load(plugin, true, 'The plugin has been added', true); // No await do it in the background
|
|
3169
3191
|
}
|
|
3170
3192
|
res.json({ message: 'Command received' });
|
|
3193
|
+
this.wssSendRefreshRequired();
|
|
3171
3194
|
return;
|
|
3172
3195
|
}
|
|
3173
3196
|
// Handle the command removeplugin from Home
|
|
@@ -3181,6 +3204,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
3181
3204
|
await this.plugins.remove(param);
|
|
3182
3205
|
}
|
|
3183
3206
|
res.json({ message: 'Command received' });
|
|
3207
|
+
this.wssSendRefreshRequired();
|
|
3184
3208
|
return;
|
|
3185
3209
|
}
|
|
3186
3210
|
// Handle the command enableplugin from Home
|
|
@@ -3205,6 +3229,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
3205
3229
|
}
|
|
3206
3230
|
}
|
|
3207
3231
|
res.json({ message: 'Command received' });
|
|
3232
|
+
this.wssSendRefreshRequired();
|
|
3208
3233
|
return;
|
|
3209
3234
|
}
|
|
3210
3235
|
// Handle the command disableplugin from Home
|
|
@@ -3220,6 +3245,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
3220
3245
|
}
|
|
3221
3246
|
}
|
|
3222
3247
|
res.json({ message: 'Command received' });
|
|
3248
|
+
this.wssSendRefreshRequired();
|
|
3223
3249
|
return;
|
|
3224
3250
|
}
|
|
3225
3251
|
});
|