matterbridge 1.2.18 → 1.2.19

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.
Files changed (31) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/dist/matterbridge.d.ts +0 -7
  3. package/dist/matterbridge.d.ts.map +1 -1
  4. package/dist/matterbridge.js +209 -197
  5. package/dist/matterbridge.js.map +1 -1
  6. package/dist/matterbridgeAccessoryPlatform.d.ts +0 -36
  7. package/dist/matterbridgeAccessoryPlatform.d.ts.map +1 -1
  8. package/dist/matterbridgeAccessoryPlatform.js +0 -48
  9. package/dist/matterbridgeAccessoryPlatform.js.map +1 -1
  10. package/dist/matterbridgeDevice.d.ts +169 -0
  11. package/dist/matterbridgeDevice.d.ts.map +1 -1
  12. package/dist/matterbridgeDevice.js +51 -21
  13. package/dist/matterbridgeDevice.js.map +1 -1
  14. package/dist/matterbridgeDynamicPlatform.d.ts +0 -36
  15. package/dist/matterbridgeDynamicPlatform.d.ts.map +1 -1
  16. package/dist/matterbridgeDynamicPlatform.js +0 -48
  17. package/dist/matterbridgeDynamicPlatform.js.map +1 -1
  18. package/dist/matterbridgePlatform.d.ts +36 -0
  19. package/dist/matterbridgePlatform.d.ts.map +1 -1
  20. package/dist/matterbridgePlatform.js +48 -0
  21. package/dist/matterbridgePlatform.js.map +1 -1
  22. package/dist/utils.d.ts +2 -1
  23. package/dist/utils.d.ts.map +1 -1
  24. package/dist/utils.js +29 -1
  25. package/dist/utils.js.map +1 -1
  26. package/frontend/build/asset-manifest.json +3 -3
  27. package/frontend/build/index.html +1 -1
  28. package/frontend/build/static/js/{main.5e82a930.js → main.23829a0f.js} +3 -3
  29. package/frontend/build/static/js/{main.5e82a930.js.map → main.23829a0f.js.map} +1 -1
  30. package/package.json +2 -2
  31. /package/frontend/build/static/js/{main.5e82a930.js.LICENSE.txt → main.23829a0f.js.LICENSE.txt} +0 -0
@@ -370,10 +370,20 @@ export class Matterbridge extends EventEmitter {
370
370
  process.exit(0);
371
371
  }
372
372
  if (hasParameter('factoryreset')) {
373
- // Delete matter storage file
374
- await fs.unlink(path.join(this.matterbridgeDirectory, 'matterbridge.json'));
375
- // Delete node storage directory with its subdirectories
376
- await fs.rm(path.join(this.matterbridgeDirectory, 'storage'), { recursive: true });
373
+ try {
374
+ // Delete matter storage file
375
+ await fs.unlink(path.join(this.matterbridgeDirectory, 'matterbridge.json'));
376
+ }
377
+ catch (err) {
378
+ this.log.error(`Error deleting storage: ${err}`);
379
+ }
380
+ try {
381
+ // Delete node storage directory with its subdirectories
382
+ await fs.rm(path.join(this.matterbridgeDirectory, 'storage'), { recursive: true });
383
+ }
384
+ catch (err) {
385
+ this.log.error(`Error removing storage directory: ${err}`);
386
+ }
377
387
  this.log.info('Factory reset done! Remove all paired devices from the controllers.');
378
388
  this.emit('shutdown');
379
389
  process.exit(0);
@@ -398,6 +408,7 @@ export class Matterbridge extends EventEmitter {
398
408
  }
399
409
  // Initialize frontend
400
410
  await this.initializeFrontend(getIntParameter('frontend'));
411
+ // Check each 60 minutes the latest versions
401
412
  this.checkUpdateInterval = setInterval(() => {
402
413
  this.getMatterbridgeLatestVersion();
403
414
  this.registeredPlugins.forEach((plugin) => {
@@ -418,18 +429,44 @@ export class Matterbridge extends EventEmitter {
418
429
  if (hasParameter('bridge')) {
419
430
  this.bridgeMode = 'bridge';
420
431
  MatterbridgeDevice.bridgeMode = 'bridge';
432
+ if (!this.storageManager) {
433
+ this.log.error('No storage manager initialized');
434
+ await this.cleanup('No storage manager initialized');
435
+ return;
436
+ }
437
+ this.log.debug('Starting matterbridge in mode', this.bridgeMode);
438
+ this.matterServer = this.createMatterServer(this.storageManager);
439
+ this.log.debug(`Creating commissioning server context for ${plg}Matterbridge${db}`);
440
+ this.matterbridgeContext = await this.createCommissioningServerContext('Matterbridge', 'Matterbridge', DeviceTypes.AGGREGATOR.code, 0xfff1, 'Matterbridge', 0x8000, 'Matterbridge Aggregator');
441
+ if (!this.matterbridgeContext) {
442
+ this.log.error(`Error creating storage context for ${plg}Matterbridge${er}`);
443
+ return;
444
+ }
445
+ if (!this.nodeContext) {
446
+ this.log.error(`Node storage context undefined for ${plg}Matterbridge${er}`);
447
+ return;
448
+ }
449
+ this.log.debug(`Creating commissioning server for ${plg}Matterbridge${db}`);
450
+ this.commissioningServer = await this.createCommisioningServer(this.matterbridgeContext, 'Matterbridge');
451
+ this.log.debug(`Creating matter aggregator for ${plg}Matterbridge${db}`);
452
+ this.matterAggregator = await this.createMatterAggregator(this.matterbridgeContext, 'Matterbridge');
453
+ this.log.debug('Adding matterbridge aggregator to commissioning server');
454
+ this.commissioningServer.addDevice(this.matterAggregator);
455
+ this.log.debug('Adding matterbridge commissioning server to matter server');
456
+ await this.matterServer.addCommissioningServer(this.commissioningServer, { uniqueStorageKey: 'Matterbridge' });
421
457
  for (const plugin of this.registeredPlugins) {
422
458
  if (!plugin.enabled) {
423
459
  this.log.info(`Plugin ${plg}${plugin.name}${nf} not enabled`);
424
460
  continue;
425
461
  }
462
+ plugin.error = false;
426
463
  plugin.loaded = false;
427
464
  plugin.started = false;
428
465
  plugin.configured = false;
429
466
  plugin.connected = undefined;
430
467
  plugin.qrPairingCode = undefined;
431
468
  plugin.manualPairingCode = undefined;
432
- this.loadPlugin(plugin); // No await do it asyncronously
469
+ this.loadPlugin(plugin, true, 'Matterbridge is starting'); // No await do it asyncronously
433
470
  }
434
471
  await this.startMatterbridge();
435
472
  return;
@@ -437,11 +474,19 @@ export class Matterbridge extends EventEmitter {
437
474
  if (hasParameter('childbridge')) {
438
475
  this.bridgeMode = 'childbridge';
439
476
  MatterbridgeDevice.bridgeMode = 'childbridge';
477
+ if (!this.storageManager) {
478
+ this.log.error('No storage manager initialized');
479
+ await this.cleanup('No storage manager initialized');
480
+ return;
481
+ }
482
+ this.log.debug('Starting matterbridge in mode', this.bridgeMode);
483
+ this.matterServer = this.createMatterServer(this.storageManager);
440
484
  for (const plugin of this.registeredPlugins) {
441
485
  if (!plugin.enabled) {
442
486
  this.log.info(`Plugin ${plg}${plugin.name}${nf} not enabled`);
443
487
  continue;
444
488
  }
489
+ plugin.error = false;
445
490
  plugin.loaded = false;
446
491
  plugin.started = false;
447
492
  plugin.configured = false;
@@ -817,42 +862,6 @@ export class Matterbridge extends EventEmitter {
817
862
  }, 3 * 1000);
818
863
  }
819
864
  }
820
- /**
821
- * Adds a device to the Matterbridge.
822
- * @param pluginName - The name of the plugin.
823
- * @param device - The device to be added.
824
- * @returns A Promise that resolves when the device is added successfully.
825
- */
826
- async addDevice(pluginName, device) {
827
- if (this.bridgeMode === 'bridge' && !this.matterAggregator) {
828
- this.log.error(`Adding device ${dev}${device.deviceName}${er} (${dev}${device.name}${er}) for plugin ${plg}${pluginName}${er} error: matterAggregator not found`);
829
- return;
830
- }
831
- this.log.debug(`Adding device ${dev}${device.deviceName}${db} (${dev}${device.name}${db}) for plugin ${plg}${pluginName}${db}`);
832
- // Check if the plugin is registered
833
- const plugin = this.registeredPlugins.find((plugin) => plugin.name === pluginName);
834
- if (!plugin) {
835
- this.log.error(`Error adding device ${dev}${device.deviceName}${er} (${dev}${device.name}${er}) plugin ${plg}${pluginName}${er} not found`);
836
- return;
837
- }
838
- // Register and add the device to matterbridge aggregator in bridge mode
839
- if (this.bridgeMode === 'bridge') {
840
- this.matterAggregator?.addBridgedDevice(device);
841
- this.registeredDevices.push({ plugin: pluginName, device, added: true });
842
- if (plugin.registeredDevices !== undefined)
843
- plugin.registeredDevices++;
844
- if (plugin.addedDevices !== undefined)
845
- plugin.addedDevices++;
846
- this.log.info(`Added and registered device (${plugin.registeredDevices}/${plugin.addedDevices}) ${dev}${device.deviceName}${nf} (${dev}${device.name}${nf}) for plugin ${plg}${pluginName}${nf}`);
847
- }
848
- // Only register the device in childbridge mode
849
- if (this.bridgeMode === 'childbridge') {
850
- this.registeredDevices.push({ plugin: pluginName, device, added: false });
851
- if (plugin.registeredDevices !== undefined)
852
- plugin.registeredDevices++;
853
- this.log.info(`Registered device (${plugin.registeredDevices}) ${dev}${device.deviceName}${nf} (${dev}${device.name}${nf}) for plugin ${plg}${pluginName}${nf}`);
854
- }
855
- }
856
865
  /**
857
866
  * Adds a bridged device to the Matterbridge.
858
867
  * @param pluginName - The name of the plugin.
@@ -874,20 +883,46 @@ export class Matterbridge extends EventEmitter {
874
883
  // Register and add the device to matterbridge aggregator in bridge mode
875
884
  if (this.bridgeMode === 'bridge') {
876
885
  this.matterAggregator?.addBridgedDevice(device);
877
- this.registeredDevices.push({ plugin: pluginName, device, added: true });
878
- if (plugin.registeredDevices !== undefined)
879
- plugin.registeredDevices++;
880
- if (plugin.addedDevices !== undefined)
881
- plugin.addedDevices++;
882
- 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}`);
883
886
  }
884
- // Only register the device in childbridge mode
887
+ // The first time create the commissioning server and the aggregator for DynamicPlatform
888
+ // Register and add the device in childbridge mode
885
889
  if (this.bridgeMode === 'childbridge') {
886
- this.registeredDevices.push({ plugin: pluginName, device, added: false });
887
- if (plugin.registeredDevices !== undefined)
888
- plugin.registeredDevices++;
889
- this.log.info(`Registered bridged device (${plugin.registeredDevices}) ${dev}${device.deviceName}${nf} (${dev}${device.name}${nf}) for plugin ${plg}${pluginName}${nf}`);
890
+ if (plugin.type === 'AccessoryPlatform') {
891
+ if (!plugin.locked) {
892
+ plugin.locked = true;
893
+ plugin.storageContext = await this.importCommissioningServerContext(plugin.name, device);
894
+ this.log.debug(`Creating commissioning server for ${plg}${plugin.name}${db}`);
895
+ plugin.commissioningServer = await this.createCommisioningServer(plugin.storageContext, plugin.name);
896
+ this.log.debug(`Adding device ${dev}${device.name}${db} to commissioning server for plugin ${plg}${plugin.name}${db}`);
897
+ plugin.commissioningServer.addDevice(device);
898
+ plugin.device = device;
899
+ this.log.debug(`Adding commissioning server to matter server for plugin ${plg}${plugin.name}${db}`);
900
+ await this.matterServer?.addCommissioningServer(plugin.commissioningServer, { uniqueStorageKey: plugin.name });
901
+ }
902
+ }
903
+ if (plugin.type === 'DynamicPlatform') {
904
+ if (!plugin.locked) {
905
+ plugin.locked = true;
906
+ this.log.debug(`Creating commissioning server context for ${plg}${plugin.name}${db}`);
907
+ plugin.storageContext = await this.createCommissioningServerContext(plugin.name, 'Matterbridge', DeviceTypes.AGGREGATOR.code, 0xfff1, 'Matterbridge', 0x8000, 'Matterbridge Dynamic Platform');
908
+ this.log.debug(`Creating commissioning server for ${plg}${plugin.name}${db}`);
909
+ plugin.commissioningServer = await this.createCommisioningServer(plugin.storageContext, plugin.name);
910
+ this.log.debug(`Creating aggregator for plugin ${plg}${plugin.name}${db}`);
911
+ plugin.aggregator = await this.createMatterAggregator(plugin.storageContext, plugin.name); // Generate serialNumber and uniqueId
912
+ this.log.debug(`Adding matter aggregator to commissioning server for plugin ${plg}${plugin.name}${db}`);
913
+ plugin.commissioningServer.addDevice(plugin.aggregator);
914
+ this.log.debug(`Adding commissioning server to matter server for plugin ${plg}${plugin.name}${db}`);
915
+ await this.matterServer?.addCommissioningServer(plugin.commissioningServer, { uniqueStorageKey: plugin.name });
916
+ }
917
+ plugin.aggregator?.addBridgedDevice(device);
918
+ }
890
919
  }
920
+ this.registeredDevices.push({ plugin: pluginName, device });
921
+ if (plugin.registeredDevices !== undefined)
922
+ plugin.registeredDevices++;
923
+ if (plugin.addedDevices !== undefined)
924
+ plugin.addedDevices++;
925
+ 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}`);
891
926
  }
892
927
  /**
893
928
  * Removes a bridged device from the Matterbridge.
@@ -1071,7 +1106,8 @@ export class Matterbridge extends EventEmitter {
1071
1106
  const schema = JSON.parse(data);
1072
1107
  schema.title = plugin.description;
1073
1108
  schema.description = plugin.name + ' v. ' + plugin.version + ' by ' + plugin.author;
1074
- this.log.debug(`Schema file found: ${schemaFile}.\nSchema:${rs}\n`, schema);
1109
+ this.log.debug(`Schema file found: ${schemaFile}.`);
1110
+ // this.log.debug(`Schema file found: ${schemaFile}.\nSchema:${rs}\n`, schema);
1075
1111
  return schema;
1076
1112
  }
1077
1113
  catch (err) {
@@ -1109,7 +1145,8 @@ export class Matterbridge extends EventEmitter {
1109
1145
  };
1110
1146
  try {
1111
1147
  await this.writeFile(schemaFile, JSON.stringify(schema, null, 2));
1112
- this.log.debug(`Created schema file: ${schemaFile}.\nSchema:${rs}\n`, schema);
1148
+ this.log.debug(`Created schema file: ${schemaFile}.`);
1149
+ // this.log.debug(`Created schema file: ${schemaFile}.\nSchema:${rs}\n`, schema);
1113
1150
  return schema;
1114
1151
  }
1115
1152
  catch (err) {
@@ -1162,7 +1199,8 @@ export class Matterbridge extends EventEmitter {
1162
1199
  await fs.access(configFile);
1163
1200
  const data = await fs.readFile(configFile, 'utf8');
1164
1201
  const config = JSON.parse(data);
1165
- this.log.debug(`Config file found: ${configFile}.\nConfig:${rs}\n`, config);
1202
+ // this.log.debug(`Config file found: ${configFile}.\nConfig:${rs}\n`, config);
1203
+ this.log.debug(`Config file found: ${configFile}.`);
1166
1204
  /* The first time a plugin is added to the system, the config file is created with the plugin name and type "".*/
1167
1205
  config.name = plugin.name;
1168
1206
  config.type = plugin.type;
@@ -1183,7 +1221,8 @@ export class Matterbridge extends EventEmitter {
1183
1221
  config = { name: plugin.name, type: plugin.type, unregisterOnShutdown: false };
1184
1222
  try {
1185
1223
  await this.writeFile(configFile, JSON.stringify(config, null, 2));
1186
- this.log.debug(`Created config file: ${configFile}.\nConfig:${rs}\n`, config);
1224
+ this.log.debug(`Created config file: ${configFile}.`);
1225
+ // this.log.debug(`Created config file: ${configFile}.\nConfig:${rs}\n`, config);
1187
1226
  return config;
1188
1227
  }
1189
1228
  catch (err) {
@@ -1214,7 +1253,8 @@ export class Matterbridge extends EventEmitter {
1214
1253
  const configFile = path.join(this.matterbridgeDirectory, `${plugin.name}.config.json`);
1215
1254
  try {
1216
1255
  await this.writeFile(configFile, JSON.stringify(plugin.platform.config, null, 2));
1217
- this.log.debug(`Saved config file: ${configFile}.\nConfig:${rs}\n`, plugin.platform.config);
1256
+ this.log.debug(`Saved config file: ${configFile}.`);
1257
+ // this.log.debug(`Saved config file: ${configFile}.\nConfig:${rs}\n`, plugin.platform.config);
1218
1258
  }
1219
1259
  catch (err) {
1220
1260
  this.log.error(`Error saving plugin ${plg}${plugin.name}${er} config: ${err}`);
@@ -1553,27 +1593,20 @@ export class Matterbridge extends EventEmitter {
1553
1593
  * @returns {Promise<void>} A promise that resolves when the Matterbridge is started.
1554
1594
  */
1555
1595
  async startMatterbridge() {
1556
- if (!this.storageManager) {
1557
- this.log.error('No storage manager initialized');
1558
- await this.cleanup('No storage manager initialized');
1559
- return;
1560
- }
1561
- this.log.debug('Starting matterbridge in mode', this.bridgeMode);
1562
- this.matterServer = this.createMatterServer(this.storageManager);
1563
1596
  if (this.bridgeMode === 'bridge') {
1564
- // Plugins are loaded by loadPlugin on startup and plugin.loaded is set to true
1565
- // Plugins are started and configured by callback when Matterbridge is commissioned
1597
+ // Plugins are loaded and started by loadPlugin on startup and plugin.loaded is set to true
1598
+ // Plugins configured by callback when Matterbridge is commissioned
1566
1599
  this.log.debug('***Starting startMatterbridge interval for Matterbridge');
1567
1600
  let failCount = 0;
1568
1601
  const startInterval = setInterval(async () => {
1569
1602
  for (const plugin of this.registeredPlugins) {
1570
1603
  if (!plugin.enabled || plugin.error)
1571
1604
  continue;
1572
- if (!plugin.loaded) {
1573
- this.log.debug(`***Waiting (failSafeCount=${failCount}/30) in startMatterbridge interval for plugin ${plg}${plugin.name}${db} loaded: ${plugin.loaded}...`);
1605
+ if (!plugin.loaded || !plugin.started) {
1606
+ this.log.debug(`***Waiting (failSafeCount=${failCount}/30) in startMatterbridge interval for plugin ${plg}${plugin.name}${db} loaded: ${plugin.loaded} started: ${plugin.started}...`);
1574
1607
  failCount++;
1575
1608
  if (failCount > 30) {
1576
- this.log.error(`***Failed to load plugin ${plg}${plugin.name}${er}`);
1609
+ this.log.error(`Error waiting for plugin ${plg}${plugin.name}${er} to load and start. Plugin is in error mode.`);
1577
1610
  plugin.error = true;
1578
1611
  }
1579
1612
  else {
@@ -1583,29 +1616,56 @@ export class Matterbridge extends EventEmitter {
1583
1616
  }
1584
1617
  clearInterval(startInterval);
1585
1618
  this.log.debug('***Cleared startMatterbridge interval for Matterbridge');
1586
- this.log.debug(`Creating commissioning server context for ${plg}Matterbridge${db}`);
1587
- this.matterbridgeContext = await this.createCommissioningServerContext('Matterbridge', 'Matterbridge', DeviceTypes.AGGREGATOR.code, 0xfff1, 'Matterbridge', 0x8000, 'Matterbridge Aggregator');
1588
- if (!this.matterbridgeContext) {
1589
- this.log.error(`Error creating storage context for ${plg}Matterbridge${er}`);
1590
- return;
1591
- }
1592
- if (!this.nodeContext) {
1593
- this.log.error(`Node storage context undefined for ${plg}Matterbridge${er}`);
1594
- return;
1595
- }
1596
- this.log.debug(`Creating commissioning server for ${plg}Matterbridge${db}`);
1597
- this.commissioningServer = await this.createCommisioningServer(this.matterbridgeContext, 'Matterbridge');
1598
- this.log.debug(`Creating matter aggregator for ${plg}Matterbridge${db}`);
1599
- this.matterAggregator = await this.createMatterAggregator(this.matterbridgeContext, 'Matterbridge');
1600
- this.log.debug('Adding matterbridge aggregator to commissioning server');
1601
- this.commissioningServer.addDevice(this.matterAggregator);
1602
- this.log.debug('Adding matterbridge commissioning server to matter server');
1603
- await this.matterServer?.addCommissioningServer(this.commissioningServer, { uniqueStorageKey: 'Matterbridge' });
1604
1619
  await this.startMatterServer();
1605
1620
  this.log.info('Matter server started');
1606
1621
  await this.showCommissioningQRCode(this.commissioningServer, this.matterbridgeContext, this.nodeContext, 'Matterbridge');
1607
- // logEndpoint(this.commissioningServer.getRootEndpoint());
1608
- // if (hasParameter('advertise')) await this.commissioningServer.advertise();
1622
+ /*
1623
+ const gdcCluster = this.commissioningServer?.getRootClusterServer(GeneralDiagnosticsCluster);
1624
+ if (gdcCluster) {
1625
+ console.log('GeneralDiagnosticsCluster', gdcCluster);
1626
+ const net = gdcCluster.getNetworkInterfacesAttribute();
1627
+ console.log('NetworkInterfaces', net);
1628
+
1629
+ // We have like "30:f6:ef:69:2b:c5" in this.systemInformation.macAddress
1630
+ const macArray = this.systemInformation.macAddress.split(':').map((hex) => parseInt(hex, 16));
1631
+ let hardwareAddress = new Uint8Array(macArray);
1632
+ if (hardwareAddress.length === 6) hardwareAddress = Uint8Array.from([0, 0, ...hardwareAddress]);
1633
+ // We have like "192.168.1.189" in this.systemInformation.ipv4Address
1634
+ const ipv4Array = this.systemInformation.ipv4Address.split('.').map((num) => parseInt(num));
1635
+ const iPv4Address = new Uint8Array(ipv4Array);
1636
+ // We have like "fd78:cbf8:4939:746:d555:85a9:74f6:9c6" in this.systemInformation.ipv6Address
1637
+ const ipv6Groups = this.systemInformation.ipv6Address.split(':');
1638
+ const ipv6Array = [];
1639
+ for (const group of ipv6Groups) {
1640
+ const decimal = parseInt(group, 16);
1641
+ ipv6Array.push(decimal >> 8); // High byte
1642
+ ipv6Array.push(decimal & 0xff); // Low byte
1643
+ }
1644
+ const iPv6Address = new Uint8Array(ipv6Array);
1645
+ this.log.warn(`GeneralDiagnosticsCluster for hardwareAddress ${this.systemInformation.macAddress} => ${debugStringify(hardwareAddress)}`);
1646
+ this.log.warn(`GeneralDiagnosticsCluster for iPv4Address ${this.systemInformation.ipv4Address} => ${debugStringify(iPv4Address)}`);
1647
+ this.log.warn(`GeneralDiagnosticsCluster for iPv6Address ${this.systemInformation.ipv6Address} => ${debugStringify(iPv6Address)}`);
1648
+ try {
1649
+ gdcCluster.setNetworkInterfacesAttribute([
1650
+ {
1651
+ name: 'eth0',
1652
+ isOperational: true,
1653
+ offPremiseServicesReachableIPv4: null,
1654
+ offPremiseServicesReachableIPv6: null,
1655
+ hardwareAddress,
1656
+ iPv4Addresses: [iPv4Address],
1657
+ iPv6Addresses: [iPv6Address],
1658
+ type: GeneralDiagnostics.InterfaceType.Ethernet,
1659
+ },
1660
+ ]);
1661
+ const net = gdcCluster.getNetworkInterfacesAttribute();
1662
+ console.log('NetworkInterfaces', net);
1663
+ } catch (error) {
1664
+ this.log.error('GeneralDiagnosticsCluster.setNetworkInterfacesAttribute error:', error);
1665
+ }
1666
+ }
1667
+ */
1668
+ // Setting reachability to true
1609
1669
  setTimeout(() => {
1610
1670
  this.log.info(`Setting reachability to true for ${plg}Matterbridge${db}`);
1611
1671
  if (this.commissioningServer)
@@ -1617,84 +1677,42 @@ export class Matterbridge extends EventEmitter {
1617
1677
  }
1618
1678
  if (this.bridgeMode === 'childbridge') {
1619
1679
  // Plugins are loaded and started by loadPlugin on startup
1620
- // addDevice and addBridgedDeevice just register the devices that are added here to the plugin commissioning server for Accessory Platform
1621
- // or to the plugin aggregator for Dynamic Platform after the commissioning is done
1680
+ // addDevice and addBridgedDeevice create the commissionig servers and add the devices to the the commissioning server or to the aggregator
1622
1681
  // Plugins are configured by callback when the plugin is commissioned
1623
- this.registeredPlugins.forEach((plugin) => {
1624
- if (!plugin.enabled)
1625
- return;
1626
- // Start the interval to check if the plugins is started
1627
- this.log.debug(`*Starting startMatterbridge interval for plugin ${plg}${plugin.name}${db} loaded: ${plugin.loaded} started: ${plugin.started}...`);
1628
- let failCount = 0;
1629
- const startInterval = setInterval(async () => {
1630
- if (!plugin.loaded || !plugin.started /* || !plugin.configured*/) {
1631
- this.log.debug(`***Waiting (failSafeCount=${failCount}/30) in startMatterbridge interval for plugin ${plg}${plugin.name}${db} loaded: ${plugin.loaded} started: ${plugin.started}...`);
1632
- failCount++;
1633
- if (failCount > 30) {
1634
- this.log.error(`***Failed to load plugin ${plg}${plugin.name}${er}`);
1635
- plugin.error = true;
1636
- clearInterval(startInterval);
1637
- }
1638
- return;
1639
- }
1640
- if (plugin.type === 'AccessoryPlatform') {
1641
- for (const registeredDevice of this.registeredDevices) {
1642
- if (registeredDevice.plugin !== plugin.name)
1643
- continue;
1644
- if (!plugin.storageContext)
1645
- plugin.storageContext = await this.importCommissioningServerContext(plugin.name, registeredDevice.device);
1646
- this.log.debug(`Creating commissioning server for ${plg}${plugin.name}${db}`);
1647
- if (!plugin.commissioningServer)
1648
- plugin.commissioningServer = await this.createCommisioningServer(plugin.storageContext, plugin.name);
1649
- this.log.debug(`Adding device ${dev}${registeredDevice.device.name}${db} to commissioning server for plugin ${plg}${plugin.name}${db}`);
1650
- plugin.commissioningServer.addDevice(registeredDevice.device);
1651
- if (!plugin.device)
1652
- plugin.device = registeredDevice.device;
1653
- }
1654
- this.log.debug(`Adding commissioning server to matter server for plugin ${plg}${plugin.name}${db}`);
1655
- if (plugin.commissioningServer)
1656
- await this.matterServer?.addCommissioningServer(plugin.commissioningServer, { uniqueStorageKey: plugin.name });
1657
- }
1658
- if (plugin.type === 'DynamicPlatform') {
1659
- this.log.debug(`Creating commissioning server context for ${plg}${plugin.name}${db}`);
1660
- plugin.storageContext = await this.createCommissioningServerContext(plugin.name, 'Matterbridge', DeviceTypes.AGGREGATOR.code, 0xfff1, 'Matterbridge', 0x8000, 'Matterbridge Dynamic Platform');
1661
- this.log.debug(`Creating commissioning server for ${plg}${plugin.name}${db}`);
1662
- plugin.commissioningServer = await this.createCommisioningServer(plugin.storageContext, plugin.name);
1663
- this.log.debug(`Creating aggregator for plugin ${plg}${plugin.name}${db}`);
1664
- plugin.aggregator = await this.createMatterAggregator(plugin.storageContext, plugin.name); // Generate serialNumber and uniqueId
1665
- this.log.debug(`Adding matter aggregator to commissioning server for plugin ${plg}${plugin.name}${db}`);
1666
- plugin.commissioningServer.addDevice(plugin.aggregator);
1667
- this.log.debug(`Adding commissioning server to matter server for plugin ${plg}${plugin.name}${db}`);
1668
- await this.matterServer?.addCommissioningServer(plugin.commissioningServer, { uniqueStorageKey: plugin.name });
1669
- }
1670
- clearInterval(startInterval);
1671
- this.log.debug(`*Cleared startMatterbridge interval for plugin ${plg}${plugin.name}${db} loaded: ${plugin.loaded} started: ${plugin.started}...`);
1672
- }, 1000);
1673
- });
1674
1682
  // Start the interval to check if all plugins are loaded and started and so start the matter server
1675
1683
  // TODO set a counter or a timeout
1676
- this.log.debug('*Starting start matter interval...');
1684
+ this.log.debug('***Starting start matter interval in childbridge mode...');
1685
+ let failCount = 0;
1677
1686
  const startMatterInterval = setInterval(async () => {
1678
1687
  let allStarted = true;
1679
1688
  this.registeredPlugins.forEach((plugin) => {
1680
- if (!plugin.enabled)
1681
- return;
1682
- if (plugin.error)
1689
+ if (!plugin.enabled || plugin.error)
1683
1690
  return;
1684
- if (plugin.enabled && (!plugin.loaded || !plugin.started))
1691
+ this.log.debug(`***Checking plugin ${plg}${plugin.name}${db} to start matter in childbridge mode...`);
1692
+ if (!plugin.loaded || !plugin.started) {
1685
1693
  allStarted = false;
1686
- if (!allStarted)
1687
- this.log.info(`***Waiting in start matter server interval for plugin ${plg}${plugin.name}${db} to load (${plugin.loaded}) and start (${plugin.started}) ...`);
1694
+ this.log.debug(`***Waiting (failSafeCount=${failCount}/30) for plugin ${plg}${plugin.name}${db} to load (${plugin.loaded}) and start (${plugin.started}) ...`);
1695
+ failCount++;
1696
+ if (failCount > 30) {
1697
+ this.log.error(`Error waiting for plugin ${plg}${plugin.name}${er} to load and start. Plugin is in error mode.`);
1698
+ plugin.error = true;
1699
+ return;
1700
+ }
1701
+ }
1688
1702
  });
1689
1703
  if (!allStarted)
1690
1704
  return;
1691
1705
  clearInterval(startMatterInterval);
1692
- this.log.info('Starting matter server...');
1706
+ this.log.debug('***Cleared startMatterbridge interval in childbridge mode');
1693
1707
  await this.startMatterServer();
1694
1708
  this.log.info('Matter server started');
1695
1709
  for (const plugin of this.registeredPlugins) {
1696
- if (!plugin.enabled)
1710
+ if (!plugin.enabled || plugin.error)
1711
+ continue;
1712
+ if (!plugin.addedDevices || plugin.addedDevices === 0) {
1713
+ this.log.error(`Plugin ${plg}${plugin.name}${er} didn't add any devices to Matterbridge. Verify the plugin configuration.`);
1697
1714
  continue;
1715
+ }
1698
1716
  if (!plugin.commissioningServer) {
1699
1717
  this.log.error(`Commissioning server not found for plugin ${plg}${plugin.name}${er}`);
1700
1718
  continue;
@@ -1709,16 +1727,16 @@ export class Matterbridge extends EventEmitter {
1709
1727
  }
1710
1728
  await this.showCommissioningQRCode(plugin.commissioningServer, plugin.storageContext, plugin.nodeContext, plugin.name);
1711
1729
  // Setting reachability to true
1712
- this.log.info(`Setting reachability to true for ${plg}${plugin.name}${db}`);
1713
- if (plugin.commissioningServer)
1714
- this.setCommissioningServerReachability(plugin.commissioningServer, true);
1715
- if (plugin.type === 'AccessoryPlatform' && plugin.device)
1716
- this.setDeviceReachability(plugin.device, true);
1717
- if (plugin.type === 'DynamicPlatform' && plugin.aggregator)
1718
- this.setAggregatorReachability(plugin.aggregator, true);
1719
- }
1720
- Logger.defaultLogLevel = this.debugEnabled ? Level.DEBUG : Level.INFO;
1721
- // clearInterval(startMatterInterval);
1730
+ setTimeout(() => {
1731
+ this.log.info(`Setting reachability to true for ${plg}${plugin.name}${db}`);
1732
+ if (plugin.commissioningServer)
1733
+ this.setCommissioningServerReachability(plugin.commissioningServer, true);
1734
+ if (plugin.type === 'AccessoryPlatform' && plugin.device)
1735
+ this.setDeviceReachability(plugin.device, true);
1736
+ if (plugin.type === 'DynamicPlatform' && plugin.aggregator)
1737
+ this.setAggregatorReachability(plugin.aggregator, true);
1738
+ }, 60 * 1000);
1739
+ }
1722
1740
  }, 1000);
1723
1741
  }
1724
1742
  }
@@ -1834,8 +1852,11 @@ export class Matterbridge extends EventEmitter {
1834
1852
  * @returns {Promise<void>} - A promise that resolves when the QR code is shown.
1835
1853
  */
1836
1854
  async showCommissioningQRCode(commissioningServer, storageContext, nodeContext, pluginName) {
1837
- if (!commissioningServer || !storageContext || !pluginName)
1855
+ if (!commissioningServer || !storageContext || !nodeContext || !pluginName) {
1856
+ this.log.error(`showCommissioningQRCode error: commissioningServer: ${!commissioningServer} storageContext: ${!storageContext} nodeContext: ${!nodeContext} pluginName: ${pluginName}`);
1857
+ await this.cleanup('No storage initialized in showCommissioningQRCode');
1838
1858
  return;
1859
+ }
1839
1860
  if (!commissioningServer.isCommissioned()) {
1840
1861
  const { qrPairingCode, manualPairingCode } = commissioningServer.getPairingCode();
1841
1862
  await storageContext.set('qrPairingCode', qrPairingCode);
@@ -1941,6 +1962,7 @@ export class Matterbridge extends EventEmitter {
1941
1962
  vendorName = '(AppleKeyChain)';
1942
1963
  break;
1943
1964
  case 4362:
1965
+ case 65521:
1944
1966
  vendorName = '(SmartThings)';
1945
1967
  break;
1946
1968
  case 4939:
@@ -2014,7 +2036,9 @@ export class Matterbridge extends EventEmitter {
2014
2036
  const info = commissioningServer.getActiveSessionInformation(fabricIndex);
2015
2037
  let connected = false;
2016
2038
  info.forEach((session) => {
2017
- this.log.info(`*Active session changed on fabric ${zb}${fabricIndex}${nf} vendor ${zb}${session.fabric?.rootVendorId}${nf} ${this.getVendorIdName(session.fabric?.rootVendorId)} ${session.fabric?.label} for ${plg}${pluginName}${nf}`, debugStringify(session));
2039
+ this.log.info(
2040
+ // eslint-disable-next-line max-len
2041
+ `*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));
2018
2042
  if (session.isPeerActive === true && session.secure === true && session.numberOfActiveSubscriptions >= 1) {
2019
2043
  this.log.info(`*Controller ${zb}${session.fabric?.rootVendorId}${nf} ${this.getVendorIdName(session.fabric?.rootVendorId)} ${session.fabric?.label} connected to ${plg}${pluginName}${nf} on session ${session.name}`);
2020
2044
  connected = true;
@@ -2029,48 +2053,32 @@ export class Matterbridge extends EventEmitter {
2029
2053
  }
2030
2054
  }
2031
2055
  setTimeout(() => {
2056
+ // We just need to configure the plugins after the controllers are connected
2032
2057
  if (this.bridgeMode === 'bridge') {
2033
- // Logger.defaultLogLevel = Level.INFO;
2034
2058
  for (const plugin of this.registeredPlugins) {
2035
- if (!plugin.enabled || !plugin.loaded || plugin.error)
2059
+ if (!plugin.enabled || !plugin.loaded || !plugin.started || plugin.error)
2036
2060
  continue;
2037
2061
  try {
2038
- this.startPlugin(plugin, 'Matterbridge is commissioned and controllers are connected', true); // No await do it asyncronously with also configurePlugin
2062
+ this.configurePlugin(plugin); // No await do it asyncronously
2039
2063
  }
2040
2064
  catch (error) {
2041
2065
  plugin.error = true;
2042
- this.log.error(`Error starting plugin ${plg}${plugin.name}${er}`, error);
2066
+ this.log.error(`Error configuring plugin ${plg}${plugin.name}${er}`, error);
2043
2067
  }
2044
2068
  }
2045
- Logger.defaultLogLevel = this.debugEnabled ? Level.DEBUG : Level.INFO;
2046
2069
  }
2047
2070
  if (this.bridgeMode === 'childbridge') {
2048
- // Logger.defaultLogLevel = Level.INFO;
2049
- const plugin = this.findPlugin(pluginName);
2050
- if (plugin && plugin.type === 'DynamicPlatform' && plugin.configured !== true) {
2051
- for (const registeredDevice of this.registeredDevices) {
2052
- if (registeredDevice.plugin === pluginName) {
2053
- this.log.info(`Adding bridged device ${dev}${registeredDevice.device.name}-${registeredDevice.device.deviceName}${nf} to aggregator for plugin ${plg}${plugin.name}${db}`);
2054
- if (!plugin.aggregator) {
2055
- this.log.error(`****Aggregator not found for plugin ${plg}${plugin.name}${er}`);
2056
- continue;
2057
- }
2058
- plugin.aggregator.addBridgedDevice(registeredDevice.device);
2059
- if (plugin.addedDevices !== undefined)
2060
- plugin.addedDevices++;
2061
- this.log.info(
2062
- // eslint-disable-next-line max-len
2063
- `Added bridged device(${plugin.registeredDevices}/${plugin.addedDevices}) ${dev}${registeredDevice.device.name}-${registeredDevice.device.deviceName}${nf} for plugin ${plg}${plugin.name}${nf}`);
2064
- registeredDevice.added = true;
2065
- }
2066
- }
2067
- }
2068
2071
  for (const plugin of this.registeredPlugins) {
2069
- if (plugin.name === pluginName && plugin.platform && plugin.configured !== true) {
2070
- this.configurePlugin(plugin); // No await do it asyncronously
2072
+ if (plugin.name === pluginName && plugin.loaded === true && plugin.started === true && plugin.configured !== true) {
2073
+ try {
2074
+ this.configurePlugin(plugin); // No await do it asyncronously
2075
+ }
2076
+ catch (error) {
2077
+ plugin.error = true;
2078
+ this.log.error(`Error configuring plugin ${plg}${plugin.name}${er}`, error);
2079
+ }
2071
2080
  }
2072
2081
  }
2073
- Logger.defaultLogLevel = this.debugEnabled ? Level.DEBUG : Level.INFO;
2074
2082
  }
2075
2083
  // logEndpoint(commissioningServer.getRootEndpoint());
2076
2084
  }, 2000);
@@ -2449,6 +2457,7 @@ export class Matterbridge extends EventEmitter {
2449
2457
  latestVersion: plugin.latestVersion,
2450
2458
  description: plugin.description,
2451
2459
  author: plugin.author,
2460
+ error: plugin.error,
2452
2461
  enabled: plugin.enabled,
2453
2462
  loaded: plugin.loaded,
2454
2463
  started: plugin.started,
@@ -2654,17 +2663,23 @@ export class Matterbridge extends EventEmitter {
2654
2663
  }
2655
2664
  try {
2656
2665
  const storedPassword = await this.nodeContext.get('password', '');
2657
- if (storedPassword === '' || password === storedPassword)
2666
+ if (storedPassword === '' || password === storedPassword) {
2667
+ this.log.debug('/api/login password valid');
2658
2668
  res.json({ valid: true });
2659
- else
2669
+ }
2670
+ else {
2671
+ this.log.warn('/api/login error wrong password');
2660
2672
  res.json({ valid: false });
2673
+ }
2661
2674
  }
2662
2675
  catch (error) {
2676
+ this.log.error('/api/login error getting password');
2663
2677
  res.json({ valid: false });
2664
2678
  }
2665
2679
  });
2666
2680
  // Endpoint to provide settings
2667
2681
  this.expressApp.get('/api/settings', express.json(), async (req, res) => {
2682
+ this.log.debug('The frontend sent /api/settings');
2668
2683
  if (!this.matterbridgeContext) {
2669
2684
  this.log.error('/api/settings matterbridgeContext not found');
2670
2685
  res.json({});
@@ -2678,15 +2693,12 @@ export class Matterbridge extends EventEmitter {
2678
2693
  }
2679
2694
  catch (error) {
2680
2695
  if (this.bridgeMode === 'bridge')
2681
- this.log.error('pairingCode for /api/settings not found');
2682
- res.json({});
2683
- return;
2696
+ this.log.error('pairingCodes for /api/settings not found');
2684
2697
  }
2685
2698
  this.matterbridgeInformation.bridgeMode = this.bridgeMode;
2686
2699
  this.matterbridgeInformation.restartMode = this.restartMode;
2687
2700
  this.matterbridgeInformation.debugEnabled = this.debugEnabled;
2688
2701
  const response = { wssHost, qrPairingCode, manualPairingCode, systemInformation: this.systemInformation, matterbridgeInformation: this.matterbridgeInformation };
2689
- this.log.debug('The frontend sent /api/settings');
2690
2702
  this.log.debug('Response:', debugStringify(response));
2691
2703
  res.json(response);
2692
2704
  });