matterbridge 3.0.8-dev-20250624-5abb0bb → 3.0.8-dev-20250625-61b3769

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/dist/frontend.js CHANGED
@@ -769,7 +769,7 @@ export class Frontend {
769
769
  this.matterbridge.devices.forEach(async (device) => {
770
770
  if (pluginName && pluginName !== device.plugin)
771
771
  return;
772
- if (!device.plugin || !device.name || !device.deviceName || !device.serialNumber || !device.uniqueId || !device.lifecycle.isReady)
772
+ if (!device.plugin || !device.deviceType || !device.name || !device.deviceName || !device.serialNumber || !device.uniqueId || !device.lifecycle.isReady)
773
773
  return;
774
774
  const cluster = this.getClusterTextFromDevice(device);
775
775
  devices.push({
@@ -198,12 +198,18 @@ export class Matterbridge extends EventEmitter {
198
198
  if (this.serverNode)
199
199
  servers.push(this.serverNode);
200
200
  }
201
- if (this.bridgeMode === 'childbridge') {
201
+ if (this.bridgeMode === 'childbridge' && this.plugins !== undefined) {
202
202
  for (const plugin of this.plugins.array()) {
203
203
  if (plugin.serverNode)
204
204
  servers.push(plugin.serverNode);
205
205
  }
206
206
  }
207
+ if (this.devices !== undefined) {
208
+ for (const device of this.devices.array()) {
209
+ if (device.serverMode === 'server' && device.serverNode)
210
+ servers.push(device.serverNode);
211
+ }
212
+ }
207
213
  await Promise.resolve();
208
214
  await this.cleanup('destroying instance...', false);
209
215
  this.log.info(`Dispose ${servers.length} MdnsService...`);
@@ -1075,6 +1081,12 @@ export class Matterbridge extends EventEmitter {
1075
1081
  }
1076
1082
  }
1077
1083
  }
1084
+ for (const device of this.devices.array()) {
1085
+ if (device.serverMode === 'server' && device.serverNode) {
1086
+ await this.stopServerNode(device.serverNode);
1087
+ device.serverNode = undefined;
1088
+ }
1089
+ }
1078
1090
  this.log.notice('Stopped matter server nodes');
1079
1091
  if (message === 'shutting down with reset...') {
1080
1092
  this.log.info('Resetting Matterbridge commissioning information...');
@@ -1168,8 +1180,18 @@ export class Matterbridge extends EventEmitter {
1168
1180
  this.log.debug('Cleanup already started...');
1169
1181
  }
1170
1182
  }
1183
+ async createDeviceServerNode(plugin, device) {
1184
+ if (device.serverMode === 'server' && !device.serverNode && device.deviceType && device.deviceName && device.vendorId && device.productId && device.vendorName && device.productName) {
1185
+ this.log.debug(`Creating device ${plg}${plugin.name}${db}:${dev}${device.deviceName}${db} server node...`);
1186
+ const storageContext = await this.createServerNodeContext(device.deviceName.replace(/[ .]/g, ''), device.deviceName, DeviceTypeId(device.deviceType), device.vendorId, device.vendorName, device.productId, device.productName);
1187
+ device.serverNode = await this.createServerNode(storageContext, this.port ? this.port++ : undefined, this.passcode ? this.passcode++ : undefined, this.discriminator ? this.discriminator++ : undefined);
1188
+ this.log.debug(`Adding ${plg}${plugin.name}${db}:${dev}${device.deviceName}${db} to server node...`);
1189
+ await device.serverNode.add(device);
1190
+ this.log.debug(`Added ${plg}${plugin.name}${db}:${dev}${device.deviceName}${db} to server node`);
1191
+ }
1192
+ }
1171
1193
  async createAccessoryPlugin(plugin, device, start = false) {
1172
- if (!plugin.locked && device.deviceName && device.vendorId && device.productId && device.vendorName && device.productName) {
1194
+ if (!plugin.locked && device.deviceType && device.deviceName && device.vendorId && device.productId && device.vendorName && device.productName) {
1173
1195
  plugin.locked = true;
1174
1196
  plugin.device = device;
1175
1197
  plugin.storageContext = await this.createServerNodeContext(plugin.name, device.deviceName, DeviceTypeId(device.deviceType), device.vendorId, device.vendorName, device.productId, device.productName);
@@ -1233,6 +1255,12 @@ export class Matterbridge extends EventEmitter {
1233
1255
  this.startMatterInterval = undefined;
1234
1256
  this.log.debug('Cleared startMatterInterval interval for Matterbridge');
1235
1257
  this.startServerNode(this.serverNode);
1258
+ for (const device of this.devices.array()) {
1259
+ if (device.serverMode === 'server' && device.serverNode) {
1260
+ this.log.debug(`Starting server node for device ${dev}${device.deviceName}${db} in server mode...`);
1261
+ await this.startServerNode(device.serverNode);
1262
+ }
1263
+ }
1236
1264
  this.configureTimeout = setTimeout(async () => {
1237
1265
  for (const plugin of this.plugins) {
1238
1266
  if (!plugin.enabled || !plugin.loaded || !plugin.started || plugin.error)
@@ -1312,7 +1340,7 @@ export class Matterbridge extends EventEmitter {
1312
1340
  }
1313
1341
  this.frontend.wssSendRefreshRequired('plugins');
1314
1342
  }, 30 * 1000);
1315
- for (const plugin of this.plugins) {
1343
+ for (const plugin of this.plugins.array()) {
1316
1344
  if (!plugin.enabled || plugin.error)
1317
1345
  continue;
1318
1346
  if (plugin.type !== 'DynamicPlatform' && (!plugin.addedDevices || plugin.addedDevices === 0)) {
@@ -1339,6 +1367,12 @@ export class Matterbridge extends EventEmitter {
1339
1367
  this.frontend.wssSendRefreshRequired('reachability');
1340
1368
  }, 60 * 1000);
1341
1369
  }
1370
+ for (const device of this.devices.array()) {
1371
+ if (device.serverMode === 'server' && device.serverNode) {
1372
+ this.log.debug(`***Starting server node for device ${plg}${device.deviceName}${db} in server mode...`);
1373
+ await this.startServerNode(device.serverNode);
1374
+ }
1375
+ }
1342
1376
  }, 1000);
1343
1377
  }
1344
1378
  async startController() {
@@ -1668,22 +1702,52 @@ export class Matterbridge extends EventEmitter {
1668
1702
  this.log.error(`Error adding bridged endpoint ${dev}${device.deviceName}${er} (${zb}${device.id}${er}) plugin ${plg}${pluginName}${er} not found`);
1669
1703
  return;
1670
1704
  }
1671
- if (this.bridgeMode === 'bridge') {
1672
- this.log.debug(`Adding bridged endpoint ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} to Matterbridge aggregator node`);
1673
- if (!this.aggregatorNode) {
1674
- this.log.error('Aggregator node not found for Matterbridge');
1675
- return;
1676
- }
1705
+ if (device.serverMode === 'server') {
1677
1706
  try {
1678
- await this.aggregatorNode.add(device);
1707
+ this.log.debug(`Creating server node for device ${dev}${device.deviceName}${db} of plugin ${plg}${plugin.name}${db}...`);
1708
+ await this.createDeviceServerNode(plugin, device);
1679
1709
  }
1680
1710
  catch (error) {
1681
1711
  const errorMessage = error instanceof Error ? error.message : error;
1682
1712
  const errorInspect = inspect(error, { depth: 10 });
1683
- this.log.error(`Error adding bridged endpoint ${dev}${device.deviceName}${er} (${zb}${device.id}${er}) for plugin ${plg}${pluginName}${er}: ${errorMessage}\nstack: ${errorInspect}`);
1713
+ this.log.error(`Error creating server node for device ${dev}${device.deviceName}${er} (${zb}${device.id}${er}) of plugin ${plg}${pluginName}${er}: ${errorMessage}\nstack: ${errorInspect}`);
1684
1714
  return;
1685
1715
  }
1686
1716
  }
1717
+ else if (this.bridgeMode === 'bridge') {
1718
+ if (device.serverMode === 'matter') {
1719
+ this.log.debug(`Adding matter endpoint ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} to Matterbridge server node...`);
1720
+ if (!this.serverNode) {
1721
+ this.log.error('Server node not found for Matterbridge');
1722
+ return;
1723
+ }
1724
+ try {
1725
+ await this.serverNode.add(device);
1726
+ }
1727
+ catch (error) {
1728
+ const errorMessage = error instanceof Error ? error.message : error;
1729
+ const errorInspect = inspect(error, { depth: 10 });
1730
+ this.log.error(`Error adding matter endpoint ${dev}${device.deviceName}${er} (${zb}${device.id}${er}) for plugin ${plg}${pluginName}${er}: ${errorMessage}\nstack: ${errorInspect}`);
1731
+ return;
1732
+ }
1733
+ }
1734
+ else {
1735
+ this.log.debug(`Adding bridged endpoint ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} to Matterbridge aggregator node`);
1736
+ if (!this.aggregatorNode) {
1737
+ this.log.error('Aggregator node not found for Matterbridge');
1738
+ return;
1739
+ }
1740
+ try {
1741
+ await this.aggregatorNode.add(device);
1742
+ }
1743
+ catch (error) {
1744
+ const errorMessage = error instanceof Error ? error.message : error;
1745
+ const errorInspect = inspect(error, { depth: 10 });
1746
+ this.log.error(`Error adding bridged endpoint ${dev}${device.deviceName}${er} (${zb}${device.id}${er}) for plugin ${plg}${pluginName}${er}: ${errorMessage}\nstack: ${errorInspect}`);
1747
+ return;
1748
+ }
1749
+ }
1750
+ }
1687
1751
  else if (this.bridgeMode === 'childbridge') {
1688
1752
  if (plugin.type === 'AccessoryPlatform') {
1689
1753
  try {
@@ -1706,11 +1770,18 @@ export class Matterbridge extends EventEmitter {
1706
1770
  this.log.debug(`Adding bridged endpoint ${dev}${device.deviceName}${db} for DynamicPlatform plugin ${plg}${plugin.name}${db} aggregator node`);
1707
1771
  await this.createDynamicPlugin(plugin);
1708
1772
  await waiter(`createDynamicPlugin(${plugin.name})`, () => plugin.serverNode?.hasParts === true);
1773
+ if (!plugin.serverNode) {
1774
+ this.log.error(`Server node not found for plugin ${plg}${plugin.name}${er}`);
1775
+ return;
1776
+ }
1709
1777
  if (!plugin.aggregatorNode) {
1710
1778
  this.log.error(`Aggregator node not found for plugin ${plg}${plugin.name}${er}`);
1711
1779
  return;
1712
1780
  }
1713
- await plugin.aggregatorNode.add(device);
1781
+ if (device.serverMode === 'matter')
1782
+ await plugin.serverNode.add(device);
1783
+ else
1784
+ await plugin.aggregatorNode.add(device);
1714
1785
  }
1715
1786
  catch (error) {
1716
1787
  const errorMessage = error instanceof Error ? error.message : error;
@@ -68,6 +68,8 @@ import { addClusterServers, addFixedLabel, addOptionalClusterServers, addRequire
68
68
  export class MatterbridgeEndpoint extends Endpoint {
69
69
  static bridgeMode = '';
70
70
  static logLevel = "info";
71
+ serverMode = undefined;
72
+ serverNode;
71
73
  log;
72
74
  plugin = undefined;
73
75
  configUrl = undefined;
@@ -83,9 +85,8 @@ export class MatterbridgeEndpoint extends Endpoint {
83
85
  hardwareVersion = undefined;
84
86
  hardwareVersionString = undefined;
85
87
  productUrl = 'https://www.npmjs.com/package/matterbridge';
86
- serverNode;
87
88
  name = undefined;
88
- deviceType;
89
+ deviceType = undefined;
89
90
  uniqueStorageKey = undefined;
90
91
  tagList = undefined;
91
92
  deviceTypes = new Map();
@@ -1,11 +1,13 @@
1
+ import EventEmitter from 'node:events';
1
2
  import { AnsiLogger, UNDERLINE, UNDERLINEOFF, BLUE, db, er, nf, nt, rs, wr } from 'node-ansi-logger';
2
3
  import { plg, typ } from './matterbridgeTypes.js';
3
- export class PluginManager {
4
+ export class PluginManager extends EventEmitter {
4
5
  _plugins = new Map();
5
6
  nodeContext;
6
7
  matterbridge;
7
8
  log;
8
9
  constructor(matterbridge) {
10
+ super();
9
11
  this.matterbridge = matterbridge;
10
12
  this.nodeContext = matterbridge.nodeContext;
11
13
  this.log = new AnsiLogger({ logName: 'PluginManager', logTimestampFormat: 4, logLevel: matterbridge.log.logLevel });
@@ -319,6 +321,7 @@ export class PluginManager {
319
321
  plugin.enabled = true;
320
322
  this.log.info(`Enabled plugin ${plg}${plugin.name}${nf}`);
321
323
  await this.saveToStorage();
324
+ this.emit('enabled', plugin.name);
322
325
  return plugin;
323
326
  }
324
327
  catch (err) {
@@ -352,6 +355,7 @@ export class PluginManager {
352
355
  plugin.enabled = false;
353
356
  this.log.info(`Disabled plugin ${plg}${plugin.name}${nf}`);
354
357
  await this.saveToStorage();
358
+ this.emit('disabled', plugin.name);
355
359
  return plugin;
356
360
  }
357
361
  catch (err) {
@@ -385,6 +389,7 @@ export class PluginManager {
385
389
  this._plugins.delete(packageJson.name);
386
390
  this.log.info(`Removed plugin ${plg}${plugin.name}${nf}`);
387
391
  await this.saveToStorage();
392
+ this.emit('removed', plugin.name);
388
393
  return plugin;
389
394
  }
390
395
  catch (err) {
@@ -419,6 +424,7 @@ export class PluginManager {
419
424
  this.log.info(`Added plugin ${plg}${packageJson.name}${nf}`);
420
425
  await this.saveToStorage();
421
426
  const plugin = this._plugins.get(packageJson.name);
427
+ this.emit('added', packageJson.name);
422
428
  return plugin || null;
423
429
  }
424
430
  catch (err) {
@@ -529,6 +535,7 @@ export class PluginManager {
529
535
  plugin.addedDevices = 0;
530
536
  await this.saveToStorage();
531
537
  this.log.notice(`Loaded plugin ${plg}${plugin.name}${nt} type ${typ}${platform.type}${nt} (entrypoint ${UNDERLINE}${pluginEntry}${UNDERLINEOFF})`);
538
+ this.emit('loaded', plugin.name);
532
539
  if (start)
533
540
  await this.start(plugin, message, false);
534
541
  if (configure)
@@ -565,6 +572,7 @@ export class PluginManager {
565
572
  this.log.notice(`Started plugin ${plg}${plugin.name}${nt} type ${typ}${plugin.type}${nt}`);
566
573
  plugin.started = true;
567
574
  await this.saveConfigFromPlugin(plugin);
575
+ this.emit('started', plugin.name);
568
576
  if (configure)
569
577
  await this.configure(plugin);
570
578
  return plugin;
@@ -597,6 +605,7 @@ export class PluginManager {
597
605
  await plugin.platform.onConfigure();
598
606
  this.log.notice(`Configured plugin ${plg}${plugin.name}${nt} type ${typ}${plugin.type}${nt}`);
599
607
  plugin.configured = true;
608
+ this.emit('configured', plugin.name);
600
609
  return plugin;
601
610
  }
602
611
  catch (err) {
@@ -640,6 +649,7 @@ export class PluginManager {
640
649
  plugin.registeredDevices = undefined;
641
650
  plugin.addedDevices = undefined;
642
651
  this.log.notice(`Shutdown of plugin ${plg}${plugin.name}${nt} completed`);
652
+ this.emit('shutdown', plugin.name);
643
653
  return plugin;
644
654
  }
645
655
  catch (err) {
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "matterbridge",
3
- "version": "3.0.8-dev-20250624-5abb0bb",
3
+ "version": "3.0.8-dev-20250625-61b3769",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "matterbridge",
9
- "version": "3.0.8-dev-20250624-5abb0bb",
9
+ "version": "3.0.8-dev-20250625-61b3769",
10
10
  "license": "Apache-2.0",
11
11
  "dependencies": {
12
12
  "@matter/main": "0.14.0",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "matterbridge",
3
- "version": "3.0.8-dev-20250624-5abb0bb",
3
+ "version": "3.0.8-dev-20250625-61b3769",
4
4
  "description": "Matterbridge plugin manager for Matter",
5
5
  "author": "https://github.com/Luligu",
6
6
  "license": "Apache-2.0",