matterbridge 2.1.4 → 2.1.5-dev.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.
Files changed (111) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/cli.js +0 -26
  3. package/dist/cluster/export.js +0 -2
  4. package/dist/defaultConfigSchema.js +0 -23
  5. package/dist/deviceManager.js +1 -94
  6. package/dist/frontend.js +23 -232
  7. package/dist/index.js +0 -28
  8. package/dist/logger/export.js +0 -1
  9. package/dist/matter/behaviors.js +0 -2
  10. package/dist/matter/clusters.js +0 -2
  11. package/dist/matter/devices.js +0 -2
  12. package/dist/matter/endpoints.js +0 -2
  13. package/dist/matter/export.js +0 -2
  14. package/dist/matter/types.js +0 -2
  15. package/dist/matterbridge.js +55 -761
  16. package/dist/matterbridgeAccessoryPlatform.js +0 -33
  17. package/dist/matterbridgeBehaviors.js +1 -32
  18. package/dist/matterbridgeDeviceTypes.js +11 -112
  19. package/dist/matterbridgeDynamicPlatform.js +0 -33
  20. package/dist/matterbridgeEndpoint.js +10 -710
  21. package/dist/matterbridgeEndpointHelpers.js +29 -105
  22. package/dist/matterbridgePlatform.js +5 -121
  23. package/dist/matterbridgeTypes.js +0 -24
  24. package/dist/pluginManager.js +3 -230
  25. package/dist/storage/export.js +0 -1
  26. package/dist/utils/colorUtils.js +2 -205
  27. package/dist/utils/export.js +0 -1
  28. package/dist/utils/utils.js +13 -267
  29. package/npm-shrinkwrap.json +2 -2
  30. package/package.json +1 -2
  31. package/dist/cli.d.ts +0 -25
  32. package/dist/cli.d.ts.map +0 -1
  33. package/dist/cli.js.map +0 -1
  34. package/dist/cluster/export.d.ts +0 -2
  35. package/dist/cluster/export.d.ts.map +0 -1
  36. package/dist/cluster/export.js.map +0 -1
  37. package/dist/defaultConfigSchema.d.ts +0 -27
  38. package/dist/defaultConfigSchema.d.ts.map +0 -1
  39. package/dist/defaultConfigSchema.js.map +0 -1
  40. package/dist/deviceManager.d.ts +0 -114
  41. package/dist/deviceManager.d.ts.map +0 -1
  42. package/dist/deviceManager.js.map +0 -1
  43. package/dist/frontend.d.ts +0 -110
  44. package/dist/frontend.d.ts.map +0 -1
  45. package/dist/frontend.js.map +0 -1
  46. package/dist/index.d.ts +0 -35
  47. package/dist/index.d.ts.map +0 -1
  48. package/dist/index.js.map +0 -1
  49. package/dist/logger/export.d.ts +0 -2
  50. package/dist/logger/export.d.ts.map +0 -1
  51. package/dist/logger/export.js.map +0 -1
  52. package/dist/matter/behaviors.d.ts +0 -2
  53. package/dist/matter/behaviors.d.ts.map +0 -1
  54. package/dist/matter/behaviors.js.map +0 -1
  55. package/dist/matter/clusters.d.ts +0 -2
  56. package/dist/matter/clusters.d.ts.map +0 -1
  57. package/dist/matter/clusters.js.map +0 -1
  58. package/dist/matter/devices.d.ts +0 -2
  59. package/dist/matter/devices.d.ts.map +0 -1
  60. package/dist/matter/devices.js.map +0 -1
  61. package/dist/matter/endpoints.d.ts +0 -2
  62. package/dist/matter/endpoints.d.ts.map +0 -1
  63. package/dist/matter/endpoints.js.map +0 -1
  64. package/dist/matter/export.d.ts +0 -5
  65. package/dist/matter/export.d.ts.map +0 -1
  66. package/dist/matter/export.js.map +0 -1
  67. package/dist/matter/types.d.ts +0 -3
  68. package/dist/matter/types.d.ts.map +0 -1
  69. package/dist/matter/types.js.map +0 -1
  70. package/dist/matterbridge.d.ts +0 -409
  71. package/dist/matterbridge.d.ts.map +0 -1
  72. package/dist/matterbridge.js.map +0 -1
  73. package/dist/matterbridgeAccessoryPlatform.d.ts +0 -39
  74. package/dist/matterbridgeAccessoryPlatform.d.ts.map +0 -1
  75. package/dist/matterbridgeAccessoryPlatform.js.map +0 -1
  76. package/dist/matterbridgeBehaviors.d.ts +0 -1056
  77. package/dist/matterbridgeBehaviors.d.ts.map +0 -1
  78. package/dist/matterbridgeBehaviors.js.map +0 -1
  79. package/dist/matterbridgeDeviceTypes.d.ts +0 -177
  80. package/dist/matterbridgeDeviceTypes.d.ts.map +0 -1
  81. package/dist/matterbridgeDeviceTypes.js.map +0 -1
  82. package/dist/matterbridgeDynamicPlatform.d.ts +0 -39
  83. package/dist/matterbridgeDynamicPlatform.d.ts.map +0 -1
  84. package/dist/matterbridgeDynamicPlatform.js.map +0 -1
  85. package/dist/matterbridgeEndpoint.d.ts +0 -834
  86. package/dist/matterbridgeEndpoint.d.ts.map +0 -1
  87. package/dist/matterbridgeEndpoint.js.map +0 -1
  88. package/dist/matterbridgeEndpointHelpers.d.ts +0 -2264
  89. package/dist/matterbridgeEndpointHelpers.d.ts.map +0 -1
  90. package/dist/matterbridgeEndpointHelpers.js.map +0 -1
  91. package/dist/matterbridgePlatform.d.ts +0 -159
  92. package/dist/matterbridgePlatform.d.ts.map +0 -1
  93. package/dist/matterbridgePlatform.js.map +0 -1
  94. package/dist/matterbridgeTypes.d.ts +0 -167
  95. package/dist/matterbridgeTypes.d.ts.map +0 -1
  96. package/dist/matterbridgeTypes.js.map +0 -1
  97. package/dist/pluginManager.d.ts +0 -236
  98. package/dist/pluginManager.d.ts.map +0 -1
  99. package/dist/pluginManager.js.map +0 -1
  100. package/dist/storage/export.d.ts +0 -2
  101. package/dist/storage/export.d.ts.map +0 -1
  102. package/dist/storage/export.js.map +0 -1
  103. package/dist/utils/colorUtils.d.ts +0 -61
  104. package/dist/utils/colorUtils.d.ts.map +0 -1
  105. package/dist/utils/colorUtils.js.map +0 -1
  106. package/dist/utils/export.d.ts +0 -3
  107. package/dist/utils/export.d.ts.map +0 -1
  108. package/dist/utils/export.js.map +0 -1
  109. package/dist/utils/utils.d.ts +0 -231
  110. package/dist/utils/utils.d.ts.map +0 -1
  111. package/dist/utils/utils.js.map +0 -1
@@ -1,26 +1,3 @@
1
- /**
2
- * This file contains the class Matterbridge.
3
- *
4
- * @file matterbridge.ts
5
- * @author Luca Liguori
6
- * @date 2023-12-29
7
- * @version 1.5.2
8
- *
9
- * Copyright 2023, 2024, 2025 Luca Liguori.
10
- *
11
- * Licensed under the Apache License, Version 2.0 (the "License");
12
- * you may not use this file except in compliance with the License.
13
- * You may obtain a copy of the License at
14
- *
15
- * http://www.apache.org/licenses/LICENSE-2.0
16
- *
17
- * Unless required by applicable law or agreed to in writing, software
18
- * distributed under the License is distributed on an "AS IS" BASIS,
19
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20
- * See the License for the specific language governing permissions and
21
- * limitations under the License. *
22
- */
23
- // Node.js modules
24
1
  import { fileURLToPath } from 'url';
25
2
  import { promises as fs } from 'fs';
26
3
  import { exec, spawn } from 'child_process';
@@ -28,27 +5,20 @@ import EventEmitter from 'events';
28
5
  import os from 'os';
29
6
  import path from 'path';
30
7
  import { randomBytes } from 'crypto';
31
- // NodeStorage and AnsiLogger modules
32
8
  import { NodeStorageManager } from './storage/export.js';
33
9
  import { AnsiLogger, UNDERLINE, UNDERLINEOFF, YELLOW, db, debugStringify, BRIGHT, RESET, er, nf, rs, wr, RED, GREEN, zb, CYAN, nt } from './logger/export.js';
34
- // Matterbridge
35
- import { logInterfaces, copyDirectory, getParameter, getIntParameter, hasParameter } from './utils/utils.js';
10
+ import { logInterfaces, copyDirectory, getParameter, getIntParameter, hasParameter, getNpmPackageVersion } from './utils/utils.js';
36
11
  import { PluginManager } from './pluginManager.js';
37
12
  import { DeviceManager } from './deviceManager.js';
38
13
  import { MatterbridgeEndpoint } from './matterbridgeEndpoint.js';
39
14
  import { bridge } from './matterbridgeDeviceTypes.js';
40
15
  import { Frontend } from './frontend.js';
41
- // @matter
42
16
  import { DeviceTypeId, Endpoint as EndpointNode, Logger, LogLevel as MatterLogLevel, LogFormat as MatterLogFormat, VendorId, StorageService, Environment, ServerNode } from '@matter/main';
43
17
  import { DeviceCommissioner, FabricAction, MdnsService, PaseClient } from '@matter/main/protocol';
44
18
  import { AggregatorEndpoint } from '@matter/main/endpoints';
45
- // Default colors
46
19
  const plg = '\u001B[38;5;33m';
47
20
  const dev = '\u001B[38;5;79m';
48
21
  const typ = '\u001B[38;5;207m';
49
- /**
50
- * Represents the Matterbridge application.
51
- */
52
22
  export class Matterbridge extends EventEmitter {
53
23
  systemInformation = {
54
24
  interfaceName: '',
@@ -85,7 +55,7 @@ export class Matterbridge extends EventEmitter {
85
55
  restartMode: '',
86
56
  readOnly: hasParameter('readonly'),
87
57
  profile: getParameter('profile'),
88
- loggerLevel: "info" /* LogLevel.INFO */,
58
+ loggerLevel: "info",
89
59
  fileLogger: false,
90
60
  matterLoggerLevel: MatterLogLevel.INFO,
91
61
  matterFileLogger: false,
@@ -120,11 +90,9 @@ export class Matterbridge extends EventEmitter {
120
90
  plugins;
121
91
  devices;
122
92
  frontend = new Frontend(this);
123
- // Matterbridge storage
124
93
  nodeStorage;
125
94
  nodeContext;
126
95
  nodeStorageName = 'storage' + (getParameter('profile') ? '.' + getParameter('profile') : '');
127
- // Cleanup
128
96
  hasCleanupStarted = false;
129
97
  initialized = false;
130
98
  execRunningCount = 0;
@@ -136,57 +104,34 @@ export class Matterbridge extends EventEmitter {
136
104
  sigtermHandler;
137
105
  exceptionHandler;
138
106
  rejectionHandler;
139
- // Matter environment
140
107
  environment = Environment.default;
141
- // Matter storage
142
108
  matterStorageName = 'matterstorage' + (getParameter('profile') ? '.' + getParameter('profile') : '');
143
109
  matterStorageService;
144
110
  matterStorageManager;
145
111
  matterbridgeContext;
146
112
  mattercontrollerContext;
147
- // Matter parameters
148
- mdnsInterface; // matter server node mdnsInterface: e.g. 'eth0' or 'wlan0' or 'WiFi'
149
- ipv4address; // matter server node listeningAddressIpv4
150
- ipv6address; // matter server node listeningAddressIpv6
151
- port; // first server node port
152
- passcode; // first server node passcode
153
- discriminator; // first server node discriminator
113
+ mdnsInterface;
114
+ ipv4address;
115
+ ipv6address;
116
+ port;
117
+ passcode;
118
+ discriminator;
154
119
  serverNode;
155
120
  aggregatorNode;
156
121
  aggregatorVendorId = VendorId(getIntParameter('vendorId') ?? 0xfff1);
157
122
  aggregatorProductId = getIntParameter('productId') ?? 0x8000;
158
123
  static instance;
159
- // We load asyncronously so is private
160
124
  constructor() {
161
125
  super();
162
126
  }
163
- /**
164
- * Retrieves the list of Matterbridge devices.
165
- * @returns {MatterbridgeEndpoint[]} An array of MatterbridgeDevice objects.
166
- */
167
127
  getDevices() {
168
128
  return this.devices.array();
169
129
  }
170
- /**
171
- * Retrieves the list of registered plugins.
172
- * @returns {RegisteredPlugin[]} An array of RegisteredPlugin objects.
173
- */
174
130
  getPlugins() {
175
131
  return this.plugins.array();
176
132
  }
177
- /** ***********************************************************************************************************************************/
178
- /** loadInstance() and cleanup() methods */
179
- /** ***********************************************************************************************************************************/
180
- /**
181
- * Loads an instance of the Matterbridge class.
182
- * If an instance already exists, return that instance.
183
- *
184
- * @param initialize - Whether to initialize the Matterbridge instance after loading.
185
- * @returns The loaded Matterbridge instance.
186
- */
187
133
  static async loadInstance(initialize = false) {
188
134
  if (!Matterbridge.instance) {
189
- // eslint-disable-next-line no-console
190
135
  if (hasParameter('debug'))
191
136
  console.log(GREEN + 'Creating a new instance of Matterbridge.', initialize ? 'Initializing...' : 'Not initializing...', rs);
192
137
  Matterbridge.instance = new Matterbridge();
@@ -195,13 +140,7 @@ export class Matterbridge extends EventEmitter {
195
140
  }
196
141
  return Matterbridge.instance;
197
142
  }
198
- /**
199
- * Call cleanup().
200
- * @deprecated This method is deprecated and is only used for jest tests.
201
- *
202
- */
203
143
  async destroyInstance() {
204
- // Save server nodes to close
205
144
  const servers = [];
206
145
  if (this.bridgeMode === 'bridge') {
207
146
  if (this.serverNode)
@@ -213,80 +152,54 @@ export class Matterbridge extends EventEmitter {
213
152
  servers.push(plugin.serverNode);
214
153
  }
215
154
  }
216
- // Cleanup
217
155
  await this.cleanup('destroying instance...', false);
218
- // Close servers mdns service
219
156
  for (const server of servers) {
220
157
  await server.env.get(MdnsService)[Symbol.asyncDispose]();
221
158
  this.log.info(`Closed ${server.id} MdnsService`);
222
159
  }
223
- // Wait for the cleanup to finish
224
160
  await new Promise((resolve) => {
225
161
  setTimeout(resolve, 1000);
226
162
  });
227
163
  }
228
- /**
229
- * Initializes the Matterbridge application.
230
- *
231
- * @remarks
232
- * This method performs the necessary setup and initialization steps for the Matterbridge application.
233
- * It displays the help information if the 'help' parameter is provided, sets up the logger, checks the
234
- * node version, registers signal handlers, initializes storage, and parses the command line.
235
- *
236
- * @returns A Promise that resolves when the initialization is complete.
237
- */
238
164
  async initialize() {
239
- // Set the restart mode
240
165
  if (hasParameter('service'))
241
166
  this.restartMode = 'service';
242
167
  if (hasParameter('docker'))
243
168
  this.restartMode = 'docker';
244
- // Set the matterbridge directory
245
169
  this.homeDirectory = getParameter('homedir') ?? os.homedir();
246
170
  this.matterbridgeDirectory = path.join(this.homeDirectory, '.matterbridge');
247
- // Setup the matter environment
248
171
  this.environment.vars.set('log.level', MatterLogLevel.INFO);
249
172
  this.environment.vars.set('log.format', MatterLogFormat.ANSI);
250
173
  this.environment.vars.set('path.root', path.join(this.matterbridgeDirectory, this.matterStorageName));
251
174
  this.environment.vars.set('runtime.signals', false);
252
175
  this.environment.vars.set('runtime.exitcode', false);
253
- // Create the matterbridge logger
254
- this.log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: hasParameter('debug') ? "debug" /* LogLevel.DEBUG */ : "info" /* LogLevel.INFO */ });
255
- // Register process handlers
176
+ this.log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4, logLevel: hasParameter('debug') ? "debug" : "info" });
256
177
  this.registerProcessHandlers();
257
- // Initialize nodeStorage and nodeContext
258
178
  try {
259
179
  this.log.debug(`Creating node storage manager: ${CYAN}${this.nodeStorageName}${db}`);
260
180
  this.nodeStorage = new NodeStorageManager({ dir: path.join(this.matterbridgeDirectory, this.nodeStorageName), writeQueue: false, expiredInterval: undefined, logging: false });
261
181
  this.log.debug('Creating node storage context for matterbridge');
262
182
  this.nodeContext = await this.nodeStorage.createStorage('matterbridge');
263
- // TODO: Remove this code when node-persist-manager is updated
264
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
265
183
  const keys = (await this.nodeStorage?.storage.keys());
266
184
  for (const key of keys) {
267
185
  this.log.debug(`Checking node storage manager key: ${CYAN}${key}${db}`);
268
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
269
186
  await this.nodeStorage?.storage.get(key);
270
187
  }
271
188
  const storages = await this.nodeStorage.getStorageNames();
272
189
  for (const storage of storages) {
273
190
  this.log.debug(`Checking storage: ${CYAN}${storage}${db}`);
274
191
  const nodeContext = await this.nodeStorage?.createStorage(storage);
275
- // TODO: Remove this code when node-persist-manager is updated
276
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
277
192
  const keys = (await nodeContext?.storage.keys());
278
193
  keys.forEach(async (key) => {
279
194
  this.log.debug(`Checking key: ${CYAN}${storage}:${key}${db}`);
280
195
  await nodeContext?.get(key);
281
196
  });
282
197
  }
283
- // Creating a backup of the node storage since it is not corrupted
284
198
  this.log.debug('Creating node storage backup...');
285
199
  await copyDirectory(path.join(this.matterbridgeDirectory, this.nodeStorageName), path.join(this.matterbridgeDirectory, this.nodeStorageName + '.backup'));
286
200
  this.log.debug('Created node storage backup');
287
201
  }
288
202
  catch (error) {
289
- // Restoring the backup of the node storage since it is corrupted
290
203
  this.log.error(`Error creating node storage manager and context: ${error instanceof Error ? error.message : error}`);
291
204
  if (hasParameter('norestore')) {
292
205
  this.log.fatal(`The matterbridge node storage is corrupted. Parameter -norestore found: exiting...`);
@@ -301,51 +214,45 @@ export class Matterbridge extends EventEmitter {
301
214
  this.log.fatal('Fatal error creating node storage manager and context for matterbridge');
302
215
  throw new Error('Fatal error creating node storage manager and context for matterbridge');
303
216
  }
304
- // Set the first port to use for the commissioning server (will be incremented in childbridge mode)
305
217
  this.port = getIntParameter('port') ?? (await this.nodeContext.get('matterport', 5540)) ?? 5540;
306
- // Set the first passcode to use for the commissioning server (will be incremented in childbridge mode)
307
218
  this.passcode = getIntParameter('passcode') ?? (await this.nodeContext.get('matterpasscode')) ?? PaseClient.generateRandomPasscode();
308
- // Set the first discriminator to use for the commissioning server (will be incremented in childbridge mode)
309
219
  this.discriminator = getIntParameter('discriminator') ?? (await this.nodeContext.get('matterdiscriminator')) ?? PaseClient.generateRandomDiscriminator();
310
220
  this.log.debug(`Initializing commissioning server for Matterbridge... on port ${this.port} with passcode ${this.passcode} and discriminator ${this.discriminator}`);
311
- // Set matterbridge logger level (context: matterbridgeLogLevel)
312
221
  if (hasParameter('logger')) {
313
222
  const level = getParameter('logger');
314
223
  if (level === 'debug') {
315
- this.log.logLevel = "debug" /* LogLevel.DEBUG */;
224
+ this.log.logLevel = "debug";
316
225
  }
317
226
  else if (level === 'info') {
318
- this.log.logLevel = "info" /* LogLevel.INFO */;
227
+ this.log.logLevel = "info";
319
228
  }
320
229
  else if (level === 'notice') {
321
- this.log.logLevel = "notice" /* LogLevel.NOTICE */;
230
+ this.log.logLevel = "notice";
322
231
  }
323
232
  else if (level === 'warn') {
324
- this.log.logLevel = "warn" /* LogLevel.WARN */;
233
+ this.log.logLevel = "warn";
325
234
  }
326
235
  else if (level === 'error') {
327
- this.log.logLevel = "error" /* LogLevel.ERROR */;
236
+ this.log.logLevel = "error";
328
237
  }
329
238
  else if (level === 'fatal') {
330
- this.log.logLevel = "fatal" /* LogLevel.FATAL */;
239
+ this.log.logLevel = "fatal";
331
240
  }
332
241
  else {
333
242
  this.log.warn(`Invalid matterbridge logger level: ${level}. Using default level "info".`);
334
- this.log.logLevel = "info" /* LogLevel.INFO */;
243
+ this.log.logLevel = "info";
335
244
  }
336
245
  }
337
246
  else {
338
- this.log.logLevel = await this.nodeContext.get('matterbridgeLogLevel', "info" /* LogLevel.INFO */);
247
+ this.log.logLevel = await this.nodeContext.get('matterbridgeLogLevel', "info");
339
248
  }
340
249
  MatterbridgeEndpoint.logLevel = this.log.logLevel;
341
- // Create the file logger for matterbridge (context: matterbridgeFileLog)
342
250
  if (hasParameter('filelogger') || (await this.nodeContext.get('matterbridgeFileLog', false))) {
343
251
  AnsiLogger.setGlobalLogfile(path.join(this.matterbridgeDirectory, this.matterbrideLoggerFile), this.log.logLevel, true);
344
252
  this.matterbridgeInformation.fileLogger = true;
345
253
  }
346
254
  this.log.notice('Matterbridge is starting...');
347
255
  this.log.debug(`Matterbridge logLevel: ${this.log.logLevel} fileLoger: ${this.matterbridgeInformation.fileLogger}.`);
348
- // Set matter.js logger level, format and logger (context: matterLogLevel)
349
256
  if (hasParameter('matterlogger')) {
350
257
  const level = getParameter('matterlogger');
351
258
  if (level === 'debug') {
@@ -376,7 +283,6 @@ export class Matterbridge extends EventEmitter {
376
283
  }
377
284
  Logger.format = MatterLogFormat.ANSI;
378
285
  Logger.setLogger('default', this.createMatterLogger());
379
- // Create the file logger for matter.js (context: matterFileLog)
380
286
  if (hasParameter('matterfilelogger') || (await this.nodeContext.get('matterFileLog', false))) {
381
287
  this.matterbridgeInformation.matterFileLogger = true;
382
288
  Logger.addLogger('matterfilelogger', await this.createMatterFileLogger(path.join(this.matterbridgeDirectory, this.matterLoggerFile), true), {
@@ -385,7 +291,6 @@ export class Matterbridge extends EventEmitter {
385
291
  });
386
292
  }
387
293
  this.log.debug(`Matter logLevel: ${Logger.defaultLogLevel} fileLoger: ${this.matterbridgeInformation.matterFileLogger}.`);
388
- // Set the interface to use for matter server node mdnsInterface
389
294
  if (hasParameter('mdnsinterface')) {
390
295
  this.mdnsInterface = getParameter('mdnsinterface');
391
296
  }
@@ -394,7 +299,6 @@ export class Matterbridge extends EventEmitter {
394
299
  if (this.mdnsInterface === '')
395
300
  this.mdnsInterface = undefined;
396
301
  }
397
- // Validate mdnsInterface
398
302
  if (this.mdnsInterface) {
399
303
  const networkInterfaces = os.networkInterfaces();
400
304
  const availableInterfaces = Object.keys(networkInterfaces);
@@ -408,7 +312,6 @@ export class Matterbridge extends EventEmitter {
408
312
  }
409
313
  if (this.mdnsInterface)
410
314
  this.environment.vars.set('mdns.networkInterface', this.mdnsInterface);
411
- // Set the listeningAddressIpv4 for the matter commissioning server
412
315
  if (hasParameter('ipv4address')) {
413
316
  this.ipv4address = getParameter('ipv4address');
414
317
  }
@@ -417,7 +320,6 @@ export class Matterbridge extends EventEmitter {
417
320
  if (this.ipv4address === '')
418
321
  this.ipv4address = undefined;
419
322
  }
420
- // Set the listeningAddressIpv6 for the matter commissioning server
421
323
  if (hasParameter('ipv6address')) {
422
324
  this.ipv6address = getParameter('ipv6address');
423
325
  }
@@ -426,19 +328,14 @@ export class Matterbridge extends EventEmitter {
426
328
  if (this.ipv6address === '')
427
329
  this.ipv6address = undefined;
428
330
  }
429
- // Initialize PluginManager
430
331
  this.plugins = new PluginManager(this);
431
332
  await this.plugins.loadFromStorage();
432
333
  this.plugins.logLevel = this.log.logLevel;
433
- // Initialize DeviceManager
434
334
  this.devices = new DeviceManager(this, this.nodeContext);
435
335
  this.devices.logLevel = this.log.logLevel;
436
- // Get the plugins from node storage and create the plugins node storage contexts
437
336
  for (const plugin of this.plugins) {
438
337
  const packageJson = await this.plugins.parse(plugin);
439
338
  if (packageJson === null && !hasParameter('add') && !hasParameter('remove') && !hasParameter('enable') && !hasParameter('disable') && !hasParameter('reset') && !hasParameter('factoryreset')) {
440
- // Try to reinstall the plugin from npm (for Docker pull and external plugins)
441
- // We don't do this when the add and other parameters are set because we shut down the process after adding the plugin
442
339
  this.log.info(`Error parsing plugin ${plg}${plugin.name}${nf}. Trying to reinstall it from npm.`);
443
340
  try {
444
341
  await this.spawnCommand('npm', ['install', '-g', plugin.name, '--omit=dev', '--verbose']);
@@ -460,7 +357,6 @@ export class Matterbridge extends EventEmitter {
460
357
  await plugin.nodeContext.set('description', plugin.description);
461
358
  await plugin.nodeContext.set('author', plugin.author);
462
359
  }
463
- // Log system info and create .matterbridge directory
464
360
  await this.logNodeAndSystemInfo();
465
361
  this.log.notice(`Matterbridge version ${this.matterbridgeVersion} ` +
466
362
  `${hasParameter('bridge') || (!hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'bridge') ? 'mode bridge ' : ''}` +
@@ -468,7 +364,6 @@ export class Matterbridge extends EventEmitter {
468
364
  `${hasParameter('controller') ? 'mode controller ' : ''}` +
469
365
  `${this.restartMode !== '' ? 'restart mode ' + this.restartMode + ' ' : ''}` +
470
366
  `running on ${this.systemInformation.osType} (v.${this.systemInformation.osRelease}) platform ${this.systemInformation.osPlatform} arch ${this.systemInformation.osArch}`);
471
- // Check node version and throw error
472
367
  const minNodeVersion = 18;
473
368
  const nodeVersion = process.versions.node;
474
369
  const versionMajor = parseInt(nodeVersion.split('.')[0]);
@@ -476,15 +371,9 @@ export class Matterbridge extends EventEmitter {
476
371
  this.log.error(`Node version ${versionMajor} is not supported. Please upgrade to ${minNodeVersion} or above.`);
477
372
  throw new Error(`Node version ${versionMajor} is not supported. Please upgrade to ${minNodeVersion} or above.`);
478
373
  }
479
- // Parse command line
480
374
  await this.parseCommandLine();
481
375
  this.initialized = true;
482
376
  }
483
- /**
484
- * Parses the command line arguments and performs the corresponding actions.
485
- * @private
486
- * @returns {Promise<void>} A promise that resolves when the command line arguments have been processed, or the process exits.
487
- */
488
377
  async parseCommandLine() {
489
378
  if (hasParameter('help')) {
490
379
  this.log.info(`\nUsage: matterbridge [options]\n
@@ -594,7 +483,6 @@ export class Matterbridge extends EventEmitter {
594
483
  await this.shutdownProcessAndFactoryReset();
595
484
  return;
596
485
  }
597
- // Start the matter storage and create the matterbridge context
598
486
  try {
599
487
  await this.startMatterStorage();
600
488
  }
@@ -602,12 +490,10 @@ export class Matterbridge extends EventEmitter {
602
490
  this.log.fatal(`Fatal error creating matter storage: ${error instanceof Error ? error.message : error}`);
603
491
  throw new Error(`Fatal error creating matter storage: ${error instanceof Error ? error.message : error}`);
604
492
  }
605
- // Clear the matterbridge context if the reset parameter is set
606
493
  if (hasParameter('reset') && getParameter('reset') === undefined) {
607
494
  await this.shutdownProcessAndReset();
608
495
  return;
609
496
  }
610
- // Clear matterbridge plugin context if the reset parameter is set
611
497
  if (hasParameter('reset') && getParameter('reset') !== undefined) {
612
498
  this.log.debug(`Reset plugin ${getParameter('reset')}`);
613
499
  const plugin = this.plugins.get(getParameter('reset'));
@@ -629,11 +515,13 @@ export class Matterbridge extends EventEmitter {
629
515
  this.emit('shutdown');
630
516
  return;
631
517
  }
632
- // Initialize frontend
633
518
  if (getIntParameter('frontend') !== 0 || getIntParameter('frontend') === undefined)
634
519
  await this.frontend.start(getIntParameter('frontend'));
635
520
  this.frontend.logLevel = this.log.logLevel;
636
- // Check each 60 minutes the latest versions
521
+ this.getMatterbridgeLatestVersion();
522
+ for (const plugin of this.plugins) {
523
+ this.getPluginLatestVersion(plugin);
524
+ }
637
525
  this.checkUpdateInterval = setInterval(() => {
638
526
  this.getMatterbridgeLatestVersion();
639
527
  for (const plugin of this.plugins) {
@@ -641,24 +529,20 @@ export class Matterbridge extends EventEmitter {
641
529
  }
642
530
  this.frontend.wssSendRefreshRequired();
643
531
  }, 60 * 60 * 1000);
644
- // Start the matterbridge in mode test
645
532
  if (hasParameter('test')) {
646
533
  this.bridgeMode = 'bridge';
647
534
  MatterbridgeEndpoint.bridgeMode = 'bridge';
648
535
  return;
649
536
  }
650
- // Start the matterbridge in mode controller
651
537
  if (hasParameter('controller')) {
652
538
  this.bridgeMode = 'controller';
653
539
  await this.startController();
654
540
  return;
655
541
  }
656
- // Check if the bridge mode is set and start matterbridge in bridge mode if not set
657
542
  if (!hasParameter('bridge') && !hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === '') {
658
543
  this.log.info('Setting default matterbridge start mode to bridge');
659
544
  await this.nodeContext?.set('bridgeMode', 'bridge');
660
545
  }
661
- // Start matterbridge in bridge mode
662
546
  if (hasParameter('bridge') || (!hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'bridge')) {
663
547
  this.bridgeMode = 'bridge';
664
548
  MatterbridgeEndpoint.bridgeMode = 'bridge';
@@ -666,7 +550,6 @@ export class Matterbridge extends EventEmitter {
666
550
  await this.startBridge();
667
551
  return;
668
552
  }
669
- // Start matterbridge in childbridge mode
670
553
  if (hasParameter('childbridge') || (!hasParameter('bridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'childbridge')) {
671
554
  this.bridgeMode = 'childbridge';
672
555
  MatterbridgeEndpoint.bridgeMode = 'childbridge';
@@ -675,28 +558,16 @@ export class Matterbridge extends EventEmitter {
675
558
  return;
676
559
  }
677
560
  }
678
- /**
679
- * Asynchronously loads and starts the registered plugins.
680
- *
681
- * This method is responsible for initializing and staarting all enabled plugins.
682
- * It ensures that each plugin is properly loaded and started before the bridge starts.
683
- *
684
- * @returns {Promise<void>} A promise that resolves when all plugins have been loaded and started.
685
- */
686
561
  async startPlugins() {
687
- // Check, load and start the plugins
688
562
  for (const plugin of this.plugins) {
689
563
  plugin.configJson = await this.plugins.loadConfig(plugin);
690
564
  plugin.schemaJson = await this.plugins.loadSchema(plugin);
691
- // Check if the plugin is available
692
565
  if (!(await this.plugins.resolve(plugin.path))) {
693
566
  this.log.error(`Plugin ${plg}${plugin.name}${er} not found or not validated. Disabling it.`);
694
567
  plugin.enabled = false;
695
568
  plugin.error = true;
696
569
  continue;
697
570
  }
698
- // Check if the plugin has a new version
699
- // this.getPluginLatestVersion(plugin); // No await do it asyncronously
700
571
  if (!plugin.enabled) {
701
572
  this.log.info(`Plugin ${plg}${plugin.name}${nf} not enabled`);
702
573
  continue;
@@ -710,26 +581,20 @@ export class Matterbridge extends EventEmitter {
710
581
  plugin.addedDevices = undefined;
711
582
  plugin.qrPairingCode = undefined;
712
583
  plugin.manualPairingCode = undefined;
713
- this.plugins.load(plugin, true, 'Matterbridge is starting'); // No await do it asyncronously
584
+ this.plugins.load(plugin, true, 'Matterbridge is starting');
714
585
  }
715
586
  this.frontend.wssSendRefreshRequired();
716
587
  }
717
- /**
718
- * Registers the process handlers for uncaughtException, unhandledRejection, SIGINT and SIGTERM.
719
- * When either of these signals are received, the cleanup method is called with an appropriate message.
720
- */
721
588
  registerProcessHandlers() {
722
589
  this.log.debug(`Registering uncaughtException and unhandledRejection handlers...`);
723
590
  process.removeAllListeners('uncaughtException');
724
591
  process.removeAllListeners('unhandledRejection');
725
592
  this.exceptionHandler = async (error) => {
726
593
  this.log.error('Unhandled Exception detected at:', error.stack || error, rs);
727
- // await this.cleanup('Unhandled Exception detected, cleaning up...');
728
594
  };
729
595
  process.on('uncaughtException', this.exceptionHandler);
730
596
  this.rejectionHandler = async (reason, promise) => {
731
597
  this.log.error('Unhandled Rejection detected at:', promise, 'reason:', reason instanceof Error ? reason.stack : reason, rs);
732
- // await this.cleanup('Unhandled Rejection detected, cleaning up...');
733
598
  };
734
599
  process.on('unhandledRejection', this.rejectionHandler);
735
600
  this.log.debug(`Registering SIGINT and SIGTERM signal handlers...`);
@@ -742,9 +607,6 @@ export class Matterbridge extends EventEmitter {
742
607
  };
743
608
  process.on('SIGTERM', this.sigtermHandler);
744
609
  }
745
- /**
746
- * Deregisters the process uncaughtException, unhandledRejection, SIGINT and SIGTERM signal handlers.
747
- */
748
610
  deregisterProcesslHandlers() {
749
611
  this.log.debug(`Deregistering uncaughtException and unhandledRejection handlers...`);
750
612
  if (this.exceptionHandler)
@@ -761,17 +623,12 @@ export class Matterbridge extends EventEmitter {
761
623
  process.off('SIGTERM', this.sigtermHandler);
762
624
  this.sigtermHandler = undefined;
763
625
  }
764
- /**
765
- * Logs the node and system information.
766
- */
767
626
  async logNodeAndSystemInfo() {
768
- // IP address information
769
627
  const networkInterfaces = os.networkInterfaces();
770
628
  this.systemInformation.interfaceName = '';
771
629
  this.systemInformation.ipv4Address = '';
772
630
  this.systemInformation.ipv6Address = '';
773
631
  for (const [interfaceName, interfaceDetails] of Object.entries(networkInterfaces)) {
774
- // this.log.debug(`Checking interface: '${interfaceName}' for '${this.mdnsInterface}'`);
775
632
  if (this.mdnsInterface && interfaceName !== this.mdnsInterface)
776
633
  continue;
777
634
  if (!interfaceDetails) {
@@ -797,22 +654,19 @@ export class Matterbridge extends EventEmitter {
797
654
  break;
798
655
  }
799
656
  }
800
- // Node information
801
657
  this.systemInformation.nodeVersion = process.versions.node;
802
658
  const versionMajor = parseInt(this.systemInformation.nodeVersion.split('.')[0]);
803
659
  const versionMinor = parseInt(this.systemInformation.nodeVersion.split('.')[1]);
804
660
  const versionPatch = parseInt(this.systemInformation.nodeVersion.split('.')[2]);
805
- // Host system information
806
661
  this.systemInformation.hostname = os.hostname();
807
662
  this.systemInformation.user = os.userInfo().username;
808
- this.systemInformation.osType = os.type(); // "Windows_NT", "Darwin", etc.
809
- this.systemInformation.osRelease = os.release(); // Kernel version
810
- this.systemInformation.osPlatform = os.platform(); // "win32", "linux", "darwin", etc.
811
- this.systemInformation.osArch = os.arch(); // "x64", "arm", etc.
812
- this.systemInformation.totalMemory = (os.totalmem() / 1024 / 1024 / 1024).toFixed(2) + ' GB'; // Convert to GB
813
- this.systemInformation.freeMemory = (os.freemem() / 1024 / 1024 / 1024).toFixed(2) + ' GB'; // Convert to GB
814
- this.systemInformation.systemUptime = (os.uptime() / 60 / 60).toFixed(2) + ' hours'; // Convert to hours
815
- // Log the system information
663
+ this.systemInformation.osType = os.type();
664
+ this.systemInformation.osRelease = os.release();
665
+ this.systemInformation.osPlatform = os.platform();
666
+ this.systemInformation.osArch = os.arch();
667
+ this.systemInformation.totalMemory = (os.totalmem() / 1024 / 1024 / 1024).toFixed(2) + ' GB';
668
+ this.systemInformation.freeMemory = (os.freemem() / 1024 / 1024 / 1024).toFixed(2) + ' GB';
669
+ this.systemInformation.systemUptime = (os.uptime() / 60 / 60).toFixed(2) + ' hours';
816
670
  this.log.debug('Host System Information:');
817
671
  this.log.debug(`- Hostname: ${this.systemInformation.hostname}`);
818
672
  this.log.debug(`- User: ${this.systemInformation.user}`);
@@ -828,19 +682,15 @@ export class Matterbridge extends EventEmitter {
828
682
  this.log.debug(`- Total Memory: ${this.systemInformation.totalMemory}`);
829
683
  this.log.debug(`- Free Memory: ${this.systemInformation.freeMemory}`);
830
684
  this.log.debug(`- System Uptime: ${this.systemInformation.systemUptime}`);
831
- // Home directory
832
685
  this.homeDirectory = getParameter('homedir') ?? os.homedir();
833
686
  this.matterbridgeInformation.homeDirectory = this.homeDirectory;
834
687
  this.log.debug(`Home Directory: ${this.homeDirectory}`);
835
- // Package root directory
836
688
  const currentFileDirectory = path.dirname(fileURLToPath(import.meta.url));
837
689
  this.rootDirectory = path.resolve(currentFileDirectory, '../');
838
690
  this.matterbridgeInformation.rootDirectory = this.rootDirectory;
839
691
  this.log.debug(`Root Directory: ${this.rootDirectory}`);
840
- // Global node_modules directory
841
692
  if (this.nodeContext)
842
693
  this.globalModulesDirectory = this.matterbridgeInformation.globalModulesDirectory = await this.nodeContext.get('globalModulesDirectory', '');
843
- // First run of Matterbridge so the node storage is empty
844
694
  if (this.globalModulesDirectory === '') {
845
695
  try {
846
696
  this.globalModulesDirectory = await this.getGlobalNodeModules();
@@ -854,20 +704,6 @@ export class Matterbridge extends EventEmitter {
854
704
  }
855
705
  else
856
706
  this.log.debug(`Global node_modules Directory: ${this.globalModulesDirectory}`);
857
- /* removed cause is too expensive for the shelly board and not really needed. Why should it change the globalModulesDirectory?
858
- else {
859
- this.getGlobalNodeModules()
860
- .then(async (globalModulesDirectory) => {
861
- this.globalModulesDirectory = globalModulesDirectory;
862
- this.matterbridgeInformation.globalModulesDirectory = this.globalModulesDirectory;
863
- this.log.debug(`Global node_modules Directory: ${this.globalModulesDirectory}`);
864
- await this.nodeContext?.set<string>('globalModulesDirectory', this.globalModulesDirectory);
865
- })
866
- .catch((error) => {
867
- this.log.error(`Error getting global node_modules directory: ${error}`);
868
- });
869
- }*/
870
- // Create the data directory .matterbridge in the home directory
871
707
  this.matterbridgeDirectory = path.join(this.homeDirectory, '.matterbridge');
872
708
  this.matterbridgeInformation.matterbridgeDirectory = this.matterbridgeDirectory;
873
709
  try {
@@ -891,7 +727,6 @@ export class Matterbridge extends EventEmitter {
891
727
  }
892
728
  }
893
729
  this.log.debug(`Matterbridge Directory: ${this.matterbridgeDirectory}`);
894
- // Create the plugin directory Matterbridge in the home directory
895
730
  this.matterbridgePluginDirectory = path.join(this.homeDirectory, 'Matterbridge');
896
731
  this.matterbridgeInformation.matterbridgePluginDirectory = this.matterbridgePluginDirectory;
897
732
  try {
@@ -915,28 +750,18 @@ export class Matterbridge extends EventEmitter {
915
750
  }
916
751
  }
917
752
  this.log.debug(`Matterbridge Plugin Directory: ${this.matterbridgePluginDirectory}`);
918
- // Matterbridge version
919
753
  const packageJson = JSON.parse(await fs.readFile(path.join(this.rootDirectory, 'package.json'), 'utf-8'));
920
754
  this.matterbridgeVersion = this.matterbridgeLatestVersion = packageJson.version;
921
755
  this.matterbridgeInformation.matterbridgeVersion = this.matterbridgeInformation.matterbridgeLatestVersion = this.matterbridgeVersion;
922
756
  this.log.debug(`Matterbridge Version: ${this.matterbridgeVersion}`);
923
- // Matterbridge latest version
924
757
  if (this.nodeContext)
925
758
  this.matterbridgeLatestVersion = await this.nodeContext.get('matterbridgeLatestVersion', this.matterbridgeVersion);
926
759
  this.log.debug(`Matterbridge Latest Version: ${this.matterbridgeLatestVersion}`);
927
- // this.getMatterbridgeLatestVersion();
928
- // Current working directory
929
760
  const currentDir = process.cwd();
930
761
  this.log.debug(`Current Working Directory: ${currentDir}`);
931
- // Command line arguments (excluding 'node' and the script name)
932
762
  const cmdArgs = process.argv.slice(2).join(' ');
933
763
  this.log.debug(`Command Line Arguments: ${cmdArgs}`);
934
764
  }
935
- /**
936
- * Retrieves the latest version of a package from the npm registry.
937
- * @param packageName - The name of the package.
938
- * @returns A Promise that resolves to the latest version of the package.
939
- */
940
765
  async getLatestVersion(packageName) {
941
766
  return new Promise((resolve, reject) => {
942
767
  this.execRunningCount++;
@@ -951,10 +776,6 @@ export class Matterbridge extends EventEmitter {
951
776
  });
952
777
  });
953
778
  }
954
- /**
955
- * Retrieves the path to the global Node.js modules directory.
956
- * @returns A promise that resolves to the path of the global Node.js modules directory.
957
- */
958
779
  async getGlobalNodeModules() {
959
780
  return new Promise((resolve, reject) => {
960
781
  this.execRunningCount++;
@@ -969,17 +790,11 @@ export class Matterbridge extends EventEmitter {
969
790
  });
970
791
  });
971
792
  }
972
- /**
973
- * Retrieves the latest version of Matterbridge and performs necessary actions based on the version comparison.
974
- * @private
975
- * @returns {Promise<void>} A promise that resolves when the latest version is retrieved and actions are performed.
976
- */
977
793
  async getMatterbridgeLatestVersion() {
978
- this.getLatestVersion('matterbridge')
979
- .then(async (matterbridgeLatestVersion) => {
980
- this.matterbridgeLatestVersion = matterbridgeLatestVersion;
981
- this.matterbridgeInformation.matterbridgeLatestVersion = this.matterbridgeLatestVersion;
982
- this.log.debug(`Matterbridge Latest Version: ${this.matterbridgeLatestVersion}`);
794
+ getNpmPackageVersion('matterbridge')
795
+ .then(async (version) => {
796
+ this.matterbridgeLatestVersion = version;
797
+ this.matterbridgeInformation.matterbridgeLatestVersion = version;
983
798
  await this.nodeContext?.set('matterbridgeLatestVersion', this.matterbridgeLatestVersion);
984
799
  if (this.matterbridgeVersion !== this.matterbridgeLatestVersion) {
985
800
  this.log.notice(`Matterbridge is out of date. Current version: ${this.matterbridgeVersion}. Latest version: ${this.matterbridgeLatestVersion}.`);
@@ -987,81 +802,57 @@ export class Matterbridge extends EventEmitter {
987
802
  else {
988
803
  this.log.debug(`Matterbridge is up to date. Current version: ${this.matterbridgeVersion}. Latest version: ${this.matterbridgeLatestVersion}.`);
989
804
  }
805
+ this.frontend.wssSendRefreshRequired();
990
806
  })
991
807
  .catch((error) => {
992
808
  this.log.error(`Error getting Matterbridge latest version: ${error.message}`);
993
- // error.stack && this.log.debug(error.stack);
994
809
  });
995
810
  }
996
- /**
997
- * Retrieves the latest version of a plugin and updates the plugin's latestVersion property.
998
- * If the plugin's version is different from the latest version, logs a warning message.
999
- * If the plugin's version is the same as the latest version, logs an info message.
1000
- * If there is an error retrieving the latest version, logs an error message.
1001
- *
1002
- * @private
1003
- * @param {RegisteredPlugin} plugin - The plugin for which to retrieve the latest version.
1004
- * @returns {Promise<void>} A promise that resolves when the latest version is retrieved and actions are performed.
1005
- */
1006
811
  async getPluginLatestVersion(plugin) {
1007
- this.getLatestVersion(plugin.name)
1008
- .then(async (latestVersion) => {
1009
- plugin.latestVersion = latestVersion;
1010
- if (plugin.version !== latestVersion)
1011
- this.log.notice(`The plugin ${plg}${plugin.name}${nt} is out of date. Current version: ${plugin.version}. Latest version: ${latestVersion}.`);
812
+ getNpmPackageVersion(plugin.name)
813
+ .then((version) => {
814
+ plugin.latestVersion = version;
815
+ if (plugin.version !== plugin.latestVersion)
816
+ this.log.notice(`The plugin ${plg}${plugin.name}${nt} is out of date. Current version: ${plugin.version}. Latest version: ${plugin.latestVersion}.`);
1012
817
  else
1013
- this.log.debug(`The plugin ${plg}${plugin.name}${db} is up to date. Current version: ${plugin.version}. Latest version: ${latestVersion}.`);
818
+ this.log.debug(`The plugin ${plg}${plugin.name}${db} is up to date. Current version: ${plugin.version}. Latest version: ${plugin.latestVersion}.`);
1014
819
  })
1015
820
  .catch((error) => {
1016
821
  this.log.error(`Error getting ${plg}${plugin.name}${er} latest version: ${error.message}`);
1017
- // error.stack && this.log.debug(error.stack);
1018
822
  });
1019
823
  }
1020
- /**
1021
- * Creates a MatterLogger function to show the matter.js log messages in AnsiLogger (for the frontend).
1022
- *
1023
- * @returns {Function} The MatterLogger function.
1024
- */
1025
824
  createMatterLogger() {
1026
- const matterLogger = new AnsiLogger({ logName: 'Matter', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: "debug" /* LogLevel.DEBUG */ });
825
+ const matterLogger = new AnsiLogger({ logName: 'Matter', logTimestampFormat: 4, logLevel: "debug" });
1027
826
  return (_level, formattedLog) => {
1028
827
  const logger = formattedLog.slice(44, 44 + 20).trim();
1029
828
  const message = formattedLog.slice(65);
1030
829
  matterLogger.logName = logger;
1031
830
  switch (_level) {
1032
831
  case MatterLogLevel.DEBUG:
1033
- matterLogger.log("debug" /* LogLevel.DEBUG */, message);
832
+ matterLogger.log("debug", message);
1034
833
  break;
1035
834
  case MatterLogLevel.INFO:
1036
- matterLogger.log("info" /* LogLevel.INFO */, message);
835
+ matterLogger.log("info", message);
1037
836
  break;
1038
837
  case MatterLogLevel.NOTICE:
1039
- matterLogger.log("notice" /* LogLevel.NOTICE */, message);
838
+ matterLogger.log("notice", message);
1040
839
  break;
1041
840
  case MatterLogLevel.WARN:
1042
- matterLogger.log("warn" /* LogLevel.WARN */, message);
841
+ matterLogger.log("warn", message);
1043
842
  break;
1044
843
  case MatterLogLevel.ERROR:
1045
- matterLogger.log("error" /* LogLevel.ERROR */, message);
844
+ matterLogger.log("error", message);
1046
845
  break;
1047
846
  case MatterLogLevel.FATAL:
1048
- matterLogger.log("fatal" /* LogLevel.FATAL */, message);
847
+ matterLogger.log("fatal", message);
1049
848
  break;
1050
849
  default:
1051
- matterLogger.log("debug" /* LogLevel.DEBUG */, message);
850
+ matterLogger.log("debug", message);
1052
851
  break;
1053
852
  }
1054
853
  };
1055
854
  }
1056
- /**
1057
- * Creates a Matter File Logger.
1058
- *
1059
- * @param {string} filePath - The path to the log file.
1060
- * @param {boolean} [unlink=false] - Whether to unlink the log file before creating a new one.
1061
- * @returns {Function} - A function that logs formatted messages to the log file.
1062
- */
1063
855
  async createMatterFileLogger(filePath, unlink = false) {
1064
- // 2024-08-21 08:55:19.488 DEBUG InteractionMessenger Sending DataReport chunk with 28 attributes and 0 events: 1004 bytes
1065
856
  let fileSize = 0;
1066
857
  if (unlink) {
1067
858
  try {
@@ -1110,21 +901,12 @@ export class Matterbridge extends EventEmitter {
1110
901
  }
1111
902
  };
1112
903
  }
1113
- /**
1114
- * Restarts the process by exiting the current instance and loading a new instance.
1115
- */
1116
904
  async restartProcess() {
1117
905
  await this.cleanup('restarting...', true);
1118
906
  }
1119
- /**
1120
- * Shut down the process by exiting the current process.
1121
- */
1122
907
  async shutdownProcess() {
1123
908
  await this.cleanup('shutting down...', false);
1124
909
  }
1125
- /**
1126
- * Update matterbridge and and shut down the process.
1127
- */
1128
910
  async updateProcess() {
1129
911
  this.log.info('Updating matterbridge...');
1130
912
  try {
@@ -1137,9 +919,6 @@ export class Matterbridge extends EventEmitter {
1137
919
  this.frontend.wssSendRestartRequired();
1138
920
  await this.cleanup('updating...', false);
1139
921
  }
1140
- /**
1141
- * Unregister all devices and shut down the process.
1142
- */
1143
922
  async unregisterAndShutdownProcess() {
1144
923
  this.log.info('Unregistering all devices and shutting down...');
1145
924
  for (const plugin of this.plugins) {
@@ -1147,9 +926,6 @@ export class Matterbridge extends EventEmitter {
1147
926
  }
1148
927
  await this.cleanup('unregistered all devices and shutting down...', false);
1149
928
  }
1150
- /**
1151
- * Reset commissioning and shut down the process.
1152
- */
1153
929
  async shutdownProcessAndReset() {
1154
930
  this.log.info('Resetting Matterbridge commissioning information...');
1155
931
  await this.matterStorageManager?.createContext('events')?.clearAll();
@@ -1161,12 +937,8 @@ export class Matterbridge extends EventEmitter {
1161
937
  this.log.info('Matter storage reset done! Remove the bridge from the controller.');
1162
938
  await this.cleanup('shutting down with reset...', false);
1163
939
  }
1164
- /**
1165
- * Factory reset and shut down the process.
1166
- */
1167
940
  async shutdownProcessAndFactoryReset() {
1168
941
  try {
1169
- // Delete old matter storage file and backup
1170
942
  const file = path.join(this.matterbridgeDirectory, 'matterbridge' + (getParameter('profile') ? '.' + getParameter('profile') : '') + '.json');
1171
943
  this.log.info(`Unlinking old matter storage file: ${file}`);
1172
944
  await fs.unlink(file);
@@ -1180,7 +952,6 @@ export class Matterbridge extends EventEmitter {
1180
952
  }
1181
953
  }
1182
954
  try {
1183
- // Delete matter node storage directory with its subdirectories and backup
1184
955
  const dir = path.join(this.matterbridgeDirectory, 'matterstorage' + (getParameter('profile') ? '.' + getParameter('profile') : ''));
1185
956
  this.log.info(`Removing matter node storage directory: ${dir}`);
1186
957
  await fs.rm(dir, { recursive: true });
@@ -1194,7 +965,6 @@ export class Matterbridge extends EventEmitter {
1194
965
  }
1195
966
  }
1196
967
  try {
1197
- // Delete node storage directory with its subdirectories and backup
1198
968
  const dir = path.join(this.matterbridgeDirectory, 'storage' + (getParameter('profile') ? '.' + getParameter('profile') : ''));
1199
969
  this.log.info(`Removing storage directory: ${dir}`);
1200
970
  await fs.rm(dir, { recursive: true });
@@ -1214,41 +984,30 @@ export class Matterbridge extends EventEmitter {
1214
984
  this.devices.clear();
1215
985
  await this.cleanup('shutting down with factory reset...', false);
1216
986
  }
1217
- /**
1218
- * Cleans up the Matterbridge instance.
1219
- * @param message - The cleanup message.
1220
- * @param restart - Indicates whether to restart the instance after cleanup. Default is `false`.
1221
- * @returns A promise that resolves when the cleanup is completed.
1222
- */
1223
987
  async cleanup(message, restart = false) {
1224
988
  if (this.initialized && !this.hasCleanupStarted) {
1225
989
  this.hasCleanupStarted = true;
1226
990
  this.log.info(message);
1227
- // Clear the start matter interval
1228
991
  if (this.startMatterInterval) {
1229
992
  clearInterval(this.startMatterInterval);
1230
993
  this.startMatterInterval = undefined;
1231
994
  this.log.debug('Start matter interval cleared');
1232
995
  }
1233
- // Clear the check update interval
1234
996
  if (this.checkUpdateInterval) {
1235
997
  clearInterval(this.checkUpdateInterval);
1236
998
  this.checkUpdateInterval = undefined;
1237
999
  this.log.debug('Check update interval cleared');
1238
1000
  }
1239
- // Clear the configure timeout
1240
1001
  if (this.configureTimeout) {
1241
1002
  clearTimeout(this.configureTimeout);
1242
1003
  this.configureTimeout = undefined;
1243
1004
  this.log.debug('Matterbridge configure timeout cleared');
1244
1005
  }
1245
- // Clear the reachability timeout
1246
1006
  if (this.reachabilityTimeout) {
1247
1007
  clearTimeout(this.reachabilityTimeout);
1248
1008
  this.reachabilityTimeout = undefined;
1249
1009
  this.log.debug('Matterbridge reachability timeout cleared');
1250
1010
  }
1251
- // Calling the shutdown method of each plugin and clear the plugins reachability timeout
1252
1011
  for (const plugin of this.plugins) {
1253
1012
  if (!plugin.enabled || plugin.error)
1254
1013
  continue;
@@ -1259,7 +1018,6 @@ export class Matterbridge extends EventEmitter {
1259
1018
  this.log.debug(`Plugin ${plg}${plugin.name}${db} reachability timeout cleared`);
1260
1019
  }
1261
1020
  }
1262
- // Stopping matter server nodes
1263
1021
  this.log.notice(`Stopping matter server nodes in ${this.bridgeMode} mode...`);
1264
1022
  if (this.bridgeMode === 'bridge') {
1265
1023
  if (this.serverNode) {
@@ -1276,37 +1034,17 @@ export class Matterbridge extends EventEmitter {
1276
1034
  }
1277
1035
  }
1278
1036
  this.log.notice('Stopped matter server nodes');
1279
- // Stop matter storage
1280
1037
  await this.stopMatterStorage();
1281
- // Stop the frontend
1282
1038
  await this.frontend.stop();
1283
- // Remove the matterfilelogger
1284
1039
  try {
1285
1040
  Logger.removeLogger('matterfilelogger');
1286
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1287
1041
  }
1288
1042
  catch (error) {
1289
- // this.log.debug(`Error removing the matterfilelogger for file ${CYAN}${path.join(this.matterbridgeDirectory, this.matterLoggerFile)}${er}: ${error instanceof Error ? error.message : error}`);
1290
1043
  }
1291
- // Serialize registeredDevices
1292
1044
  if (this.nodeStorage && this.nodeContext) {
1293
- /*
1294
- TODO: Implement serialization of registered devices in edge mode
1295
- this.log.info('Saving registered devices...');
1296
- const serializedRegisteredDevices: SerializedMatterbridgeEndpoint[] = [];
1297
- this.devices.forEach(async (device) => {
1298
- const serializedMatterbridgeDevice = MatterbridgeEndpoint.serialize(device);
1299
- // this.log.info(`- ${serializedMatterbridgeDevice.deviceName}${rs}\n`, serializedMatterbridgeDevice);
1300
- if (serializedMatterbridgeDevice) serializedRegisteredDevices.push(serializedMatterbridgeDevice);
1301
- });
1302
- await this.nodeContext.set<SerializedMatterbridgeEndpoint[]>('devices', serializedRegisteredDevices);
1303
- this.log.info(`Saved registered devices (${serializedRegisteredDevices?.length})`);
1304
- */
1305
- // Clear nodeContext and nodeStorage (they just need 1000ms to write the data to disk)
1306
1045
  this.log.debug(`Closing node storage context for ${plg}Matterbridge${db}...`);
1307
1046
  await this.nodeContext.close();
1308
1047
  this.nodeContext = undefined;
1309
- // Clear nodeContext for each plugin (they just need 1000ms to write the data to disk)
1310
1048
  for (const plugin of this.plugins) {
1311
1049
  if (plugin.nodeContext) {
1312
1050
  this.log.debug(`Closing node storage context for plugin ${plg}${plugin.name}${db}...`);
@@ -1323,13 +1061,12 @@ export class Matterbridge extends EventEmitter {
1323
1061
  }
1324
1062
  this.plugins.clear();
1325
1063
  this.devices.clear();
1326
- // Deregisters the process handlers
1327
1064
  this.deregisterProcesslHandlers();
1328
1065
  if (restart) {
1329
1066
  if (message === 'updating...') {
1330
1067
  this.log.info('Cleanup completed. Updating...');
1331
1068
  Matterbridge.instance = undefined;
1332
- this.emit('update'); // Restart the process but the update has been done before
1069
+ this.emit('update');
1333
1070
  }
1334
1071
  else if (message === 'restarting...') {
1335
1072
  this.log.info('Cleanup completed. Restarting...');
@@ -1349,14 +1086,6 @@ export class Matterbridge extends EventEmitter {
1349
1086
  this.log.debug('Cleanup already started...');
1350
1087
  }
1351
1088
  }
1352
- /**
1353
- * Creates and configures the server node for an accessory plugin for a given device.
1354
- *
1355
- * @param {RegisteredPlugin} plugin - The plugin to configure.
1356
- * @param {MatterbridgeEndpoint} device - The device to associate with the plugin.
1357
- * @param {boolean} [start=false] - Whether to start the server node after adding the device.
1358
- * @returns {Promise<void>} A promise that resolves when the server node for the accessory plugin is created and configured.
1359
- */
1360
1089
  async createAccessoryPlugin(plugin, device, start = false) {
1361
1090
  if (!plugin.locked && device.deviceName && device.vendorId && device.productId && device.vendorName && device.productName) {
1362
1091
  plugin.locked = true;
@@ -1368,13 +1097,6 @@ export class Matterbridge extends EventEmitter {
1368
1097
  await this.startServerNode(plugin.serverNode);
1369
1098
  }
1370
1099
  }
1371
- /**
1372
- * Creates and configures the server node for a dynamic plugin.
1373
- *
1374
- * @param {RegisteredPlugin} plugin - The plugin to configure.
1375
- * @param {boolean} [start=false] - Whether to start the server node after adding the aggregator node.
1376
- * @returns {Promise<void>} A promise that resolves when the server node for the dynamic plugin is created and configured.
1377
- */
1378
1100
  async createDynamicPlugin(plugin, start = false) {
1379
1101
  if (!plugin.locked) {
1380
1102
  plugin.locked = true;
@@ -1386,13 +1108,7 @@ export class Matterbridge extends EventEmitter {
1386
1108
  await this.startServerNode(plugin.serverNode);
1387
1109
  }
1388
1110
  }
1389
- /**
1390
- * Starts the Matterbridge in bridge mode.
1391
- * @private
1392
- * @returns {Promise<void>} A promise that resolves when the Matterbridge is started.
1393
- */
1394
1111
  async startBridge() {
1395
- // Plugins are configured by a timer when matter server is started and plugin.configured is set to true
1396
1112
  if (!this.matterStorageManager)
1397
1113
  throw new Error('No storage manager initialized');
1398
1114
  if (!this.matterbridgeContext)
@@ -1429,9 +1145,7 @@ export class Matterbridge extends EventEmitter {
1429
1145
  clearInterval(this.startMatterInterval);
1430
1146
  this.startMatterInterval = undefined;
1431
1147
  this.log.debug('Cleared startMatterInterval interval for Matterbridge');
1432
- // Start the Matter server node
1433
1148
  this.startServerNode(this.serverNode);
1434
- // Configure the plugins
1435
1149
  this.configureTimeout = setTimeout(async () => {
1436
1150
  for (const plugin of this.plugins) {
1437
1151
  if (!plugin.enabled || !plugin.loaded || !plugin.started || plugin.error)
@@ -1446,7 +1160,6 @@ export class Matterbridge extends EventEmitter {
1446
1160
  }
1447
1161
  this.frontend.wssSendRefreshRequired();
1448
1162
  }, 30 * 1000);
1449
- // Setting reachability to true
1450
1163
  this.reachabilityTimeout = setTimeout(() => {
1451
1164
  this.log.info(`Setting reachability to true for ${plg}Matterbridge${db}`);
1452
1165
  if (this.serverNode)
@@ -1457,14 +1170,7 @@ export class Matterbridge extends EventEmitter {
1457
1170
  }, 60 * 1000);
1458
1171
  }, 1000);
1459
1172
  }
1460
- /**
1461
- * Starts the Matterbridge in childbridge mode.
1462
- * @private
1463
- * @returns {Promise<void>} A promise that resolves when the Matterbridge is started.
1464
- */
1465
1173
  async startChildbridge() {
1466
- // Matterbridge.addBridgedDevice creates the commissionig servers and add the devices to the the commissioning server or to the aggregator
1467
- // Plugins are configured by a timer when matter server is started and plugin.configured is set to true
1468
1174
  if (!this.matterStorageManager)
1469
1175
  throw new Error('No storage manager initialized');
1470
1176
  for (const plugin of this.plugins) {
@@ -1511,13 +1217,12 @@ export class Matterbridge extends EventEmitter {
1511
1217
  clearInterval(this.startMatterInterval);
1512
1218
  this.startMatterInterval = undefined;
1513
1219
  this.log.debug('Cleared startMatterInterval interval in childbridge mode');
1514
- // Configure the plugins
1515
1220
  this.configureTimeout = setTimeout(async () => {
1516
1221
  for (const plugin of this.plugins) {
1517
1222
  if (!plugin.enabled || !plugin.loaded || !plugin.started || plugin.error)
1518
1223
  continue;
1519
1224
  try {
1520
- await this.plugins.configure(plugin); // TODO No await do it in parallel
1225
+ await this.plugins.configure(plugin);
1521
1226
  }
1522
1227
  catch (error) {
1523
1228
  plugin.error = true;
@@ -1545,9 +1250,7 @@ export class Matterbridge extends EventEmitter {
1545
1250
  this.log.error(`Node storage context not found for plugin ${plg}${plugin.name}${er}`);
1546
1251
  continue;
1547
1252
  }
1548
- // Start the Matter server node
1549
1253
  this.startServerNode(plugin.serverNode);
1550
- // Setting reachability to true
1551
1254
  plugin.reachabilityTimeout = setTimeout(() => {
1552
1255
  this.log.info(`Setting reachability to true for ${plg}${plugin.name}${db}`);
1553
1256
  if (plugin.serverNode)
@@ -1561,219 +1264,9 @@ export class Matterbridge extends EventEmitter {
1561
1264
  }
1562
1265
  }, 1000);
1563
1266
  }
1564
- /**
1565
- * Starts the Matterbridge controller.
1566
- * @private
1567
- * @returns {Promise<void>} A promise that resolves when the Matterbridge is started.
1568
- */
1569
1267
  async startController() {
1570
- /*
1571
- if (!this.storageManager) {
1572
- this.log.error('No storage manager initialized');
1573
- await this.cleanup('No storage manager initialized');
1574
- return;
1575
- }
1576
- this.log.info('Creating context: mattercontrollerContext');
1577
- this.mattercontrollerContext = this.storageManager.createContext('mattercontrollerContext');
1578
- if (!this.mattercontrollerContext) {
1579
- this.log.error('No storage context mattercontrollerContext initialized');
1580
- await this.cleanup('No storage context mattercontrollerContext initialized');
1581
- return;
1582
- }
1583
-
1584
- this.log.debug('Starting matterbridge in mode', this.bridgeMode);
1585
- this.matterServer = await this.createMatterServer(this.storageManager);
1586
- this.log.info('Creating matter commissioning controller');
1587
- this.commissioningController = new CommissioningController({
1588
- autoConnect: false,
1589
- });
1590
- this.log.info('Adding matter commissioning controller to matter server');
1591
- await this.matterServer.addCommissioningController(this.commissioningController);
1592
-
1593
- this.log.info('Starting matter server');
1594
- await this.matterServer.start();
1595
- this.log.info('Matter server started');
1596
-
1597
- if (hasParameter('pairingcode')) {
1598
- this.log.info('Pairing device with pairingcode:', getParameter('pairingcode'));
1599
- const pairingCode = getParameter('pairingcode');
1600
- const ip = this.mattercontrollerContext.has('ip') ? this.mattercontrollerContext.get<string>('ip') : undefined;
1601
- const port = this.mattercontrollerContext.has('port') ? this.mattercontrollerContext.get<number>('port') : undefined;
1602
-
1603
- let longDiscriminator, setupPin, shortDiscriminator;
1604
- if (pairingCode !== undefined) {
1605
- const pairingCodeCodec = ManualPairingCodeCodec.decode(pairingCode);
1606
- shortDiscriminator = pairingCodeCodec.shortDiscriminator;
1607
- longDiscriminator = undefined;
1608
- setupPin = pairingCodeCodec.passcode;
1609
- this.log.info(`Data extracted from pairing code: ${Logger.toJSON(pairingCodeCodec)}`);
1610
- } else {
1611
- longDiscriminator = await this.mattercontrollerContext.get('longDiscriminator', 3840);
1612
- if (longDiscriminator > 4095) throw new Error('Discriminator value must be less than 4096');
1613
- setupPin = this.mattercontrollerContext.get('pin', 20202021);
1614
- }
1615
- if ((shortDiscriminator === undefined && longDiscriminator === undefined) || setupPin === undefined) {
1616
- throw new Error('Please specify the longDiscriminator of the device to commission with -longDiscriminator or provide a valid passcode with -passcode');
1617
- }
1618
-
1619
- const commissioningOptions: ControllerCommissioningFlowOptions = {
1620
- regulatoryLocation: GeneralCommissioning.RegulatoryLocationType.IndoorOutdoor,
1621
- regulatoryCountryCode: 'XX',
1622
- };
1623
- const options = {
1624
- commissioning: commissioningOptions,
1625
- discovery: {
1626
- knownAddress: ip !== undefined && port !== undefined ? { ip, port, type: 'udp' } : undefined,
1627
- identifierData: longDiscriminator !== undefined ? { longDiscriminator } : shortDiscriminator !== undefined ? { shortDiscriminator } : {},
1628
- },
1629
- passcode: setupPin,
1630
- } as NodeCommissioningOptions;
1631
- this.log.info('Commissioning with options:', options);
1632
- const nodeId = await this.commissioningController.commissionNode(options);
1633
- this.log.info(`Commissioning successfully done with nodeId: ${nodeId}`);
1634
- this.log.info('ActiveSessionInformation:', this.commissioningController.getActiveSessionInformation());
1635
- } // (hasParameter('pairingcode'))
1636
-
1637
- if (hasParameter('unpairall')) {
1638
- this.log.info('***Commissioning controller unpairing all nodes...');
1639
- const nodeIds = this.commissioningController.getCommissionedNodes();
1640
- for (const nodeId of nodeIds) {
1641
- this.log.info('***Commissioning controller unpairing node:', nodeId);
1642
- await this.commissioningController.removeNode(nodeId);
1643
- }
1644
- return;
1645
- }
1646
-
1647
- if (hasParameter('discover')) {
1648
- // const discover = await this.commissioningController.discoverCommissionableDevices({ productId: 0x8000, deviceType: 0xfff1 });
1649
- // console.log(discover);
1650
- }
1651
-
1652
- if (!this.commissioningController.isCommissioned()) {
1653
- this.log.info('***Commissioning controller is not commissioned: use matterbridge -controller -pairingcode [pairingcode] to commission a device');
1654
- return;
1655
- }
1656
-
1657
- const nodeIds = this.commissioningController.getCommissionedNodes();
1658
- this.log.info(`***Commissioning controller is commissioned ${this.commissioningController.isCommissioned()} and has ${nodeIds.length} nodes commisioned: `);
1659
- for (const nodeId of nodeIds) {
1660
- this.log.info(`***Connecting to commissioned node: ${nodeId}`);
1661
-
1662
- const node = await this.commissioningController.connectNode(nodeId, {
1663
- autoSubscribe: false,
1664
- attributeChangedCallback: (peerNodeId, { path: { nodeId, clusterId, endpointId, attributeName }, value }) =>
1665
- this.log.info(`***Commissioning controller attributeChangedCallback ${peerNodeId}: attribute ${nodeId}/${endpointId}/${clusterId}/${attributeName} changed to ${Logger.toJSON(value)}`),
1666
- eventTriggeredCallback: (peerNodeId, { path: { nodeId, clusterId, endpointId, eventName }, events }) =>
1667
- this.log.info(`***Commissioning controller eventTriggeredCallback ${peerNodeId}: Event ${nodeId}/${endpointId}/${clusterId}/${eventName} triggered with ${Logger.toJSON(events)}`),
1668
- stateInformationCallback: (peerNodeId, info) => {
1669
- switch (info) {
1670
- case NodeStateInformation.Connected:
1671
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} connected`);
1672
- break;
1673
- case NodeStateInformation.Disconnected:
1674
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} disconnected`);
1675
- break;
1676
- case NodeStateInformation.Reconnecting:
1677
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} reconnecting`);
1678
- break;
1679
- case NodeStateInformation.WaitingForDeviceDiscovery:
1680
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} waiting for device discovery`);
1681
- break;
1682
- case NodeStateInformation.StructureChanged:
1683
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} structure changed`);
1684
- break;
1685
- case NodeStateInformation.Decommissioned:
1686
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} decommissioned`);
1687
- break;
1688
- default:
1689
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} NodeStateInformation.${info}`);
1690
- break;
1691
- }
1692
- },
1693
- });
1694
-
1695
- node.logStructure();
1696
-
1697
- // Get the interaction client
1698
- this.log.info('Getting the interaction client');
1699
- const interactionClient = await node.getInteractionClient();
1700
- let cluster;
1701
- let attributes;
1702
-
1703
- // Log BasicInformationCluster
1704
- cluster = BasicInformationCluster;
1705
- attributes = await interactionClient.getMultipleAttributes({
1706
- attributes: [{ clusterId: cluster.id }],
1707
- });
1708
- if (attributes.length > 0) this.log.info(`Cluster: ${idn}${cluster.name}${rs}${nf} attributes:`);
1709
- attributes.forEach((attribute) => {
1710
- this.log.info(
1711
- `- endpoint ${or}${attribute.path.endpointId}${nf} cluster ${hk}${getClusterNameById(attribute.path.clusterId)}${nf} (${hk}0x${attribute.path.clusterId.toString(16)}${nf}) attribute ${zb}${attribute.path.attributeName}${nf} (${zb}0x${attribute.path.attributeId.toString(16)}${nf}): ${typeof attribute.value === 'object' ? stringify(attribute.value) : attribute.value}`,
1712
- );
1713
- });
1714
-
1715
- // Log PowerSourceCluster
1716
- cluster = PowerSourceCluster;
1717
- attributes = await interactionClient.getMultipleAttributes({
1718
- attributes: [{ clusterId: cluster.id }],
1719
- });
1720
- if (attributes.length > 0) this.log.info(`Cluster: ${idn}${cluster.name}${rs}${nf} attributes:`);
1721
- attributes.forEach((attribute) => {
1722
- this.log.info(
1723
- `- endpoint ${or}${attribute.path.endpointId}${nf} cluster ${hk}${getClusterNameById(attribute.path.clusterId)}${nf} (${hk}0x${attribute.path.clusterId.toString(16)}${nf}) attribute ${zb}${attribute.path.attributeName}${nf} (${zb}0x${attribute.path.attributeId.toString(16)}${nf}): ${typeof attribute.value === 'object' ? stringify(attribute.value) : attribute.value}`,
1724
- );
1725
- });
1726
-
1727
- // Log ThreadNetworkDiagnostics
1728
- cluster = ThreadNetworkDiagnosticsCluster;
1729
- attributes = await interactionClient.getMultipleAttributes({
1730
- attributes: [{ clusterId: cluster.id }],
1731
- });
1732
- if (attributes.length > 0) this.log.info(`Cluster: ${idn}${cluster.name}${rs}${nf} attributes:`);
1733
- attributes.forEach((attribute) => {
1734
- this.log.info(
1735
- `- endpoint ${or}${attribute.path.endpointId}${nf} cluster ${hk}${getClusterNameById(attribute.path.clusterId)}${nf} (${hk}0x${attribute.path.clusterId.toString(16)}${nf}) attribute ${zb}${attribute.path.attributeName}${nf} (${zb}0x${attribute.path.attributeId.toString(16)}${nf}): ${typeof attribute.value === 'object' ? stringify(attribute.value) : attribute.value}`,
1736
- );
1737
- });
1738
-
1739
- // Log SwitchCluster
1740
- cluster = SwitchCluster;
1741
- attributes = await interactionClient.getMultipleAttributes({
1742
- attributes: [{ clusterId: cluster.id }],
1743
- });
1744
- if (attributes.length > 0) this.log.info(`Cluster: ${idn}${cluster.name}${rs}${nf} attributes:`);
1745
- attributes.forEach((attribute) => {
1746
- this.log.info(
1747
- `- endpoint ${or}${attribute.path.endpointId}${nf} cluster ${hk}${getClusterNameById(attribute.path.clusterId)}${nf} (${hk}0x${attribute.path.clusterId.toString(16)}${nf}) attribute ${zb}${attribute.path.attributeName}${nf} (${zb}0x${attribute.path.attributeId.toString(16)}${nf}): ${typeof attribute.value === 'object' ? stringify(attribute.value) : attribute.value}`,
1748
- );
1749
- });
1750
-
1751
- this.log.info('Subscribing to all attributes and events');
1752
- await node.subscribeAllAttributesAndEvents({
1753
- ignoreInitialTriggers: false,
1754
- attributeChangedCallback: ({ path: { nodeId, clusterId, endpointId, attributeName }, version, value }) =>
1755
- this.log.info(
1756
- `***${db}Commissioning controller attributeChangedCallback version ${version}: attribute ${BLUE}${nodeId}${db}/${or}${endpointId}${db}/${hk}${getClusterNameById(clusterId)}${db}/${zb}${attributeName}${db} changed to ${typeof value === 'object' ? debugStringify(value ?? { none: true }) : value}`,
1757
- ),
1758
- eventTriggeredCallback: ({ path: { nodeId, clusterId, endpointId, eventName }, events }) => {
1759
- this.log.info(
1760
- `***${db}Commissioning controller eventTriggeredCallback: event ${BLUE}${nodeId}${db}/${or}${endpointId}${db}/${hk}${getClusterNameById(clusterId)}${db}/${zb}${eventName}${db} triggered with ${debugStringify(events ?? { none: true })}`,
1761
- );
1762
- },
1763
- });
1764
- this.log.info('Subscribed to all attributes and events');
1765
- }
1766
- */
1767
1268
  }
1768
- /** ***********************************************************************************************************************************/
1769
- /** Matter.js methods */
1770
- /** ***********************************************************************************************************************************/
1771
- /**
1772
- * Starts the matter storage process with name Matterbridge.
1773
- * @returns {Promise<void>} - A promise that resolves when the storage process is started.
1774
- */
1775
1269
  async startMatterStorage() {
1776
- // Setup Matter storage
1777
1270
  this.log.info(`Starting matter node storage...`);
1778
1271
  this.matterStorageService = this.environment.get(StorageService);
1779
1272
  this.log.info(`Matter node storage service created: ${this.matterStorageService.location}`);
@@ -1781,25 +1274,13 @@ export class Matterbridge extends EventEmitter {
1781
1274
  this.log.info('Matter node storage manager "Matterbridge" created');
1782
1275
  this.matterbridgeContext = await this.createServerNodeContext('Matterbridge', 'Matterbridge', bridge.code, this.aggregatorVendorId, 'Matterbridge', this.aggregatorProductId, 'Matterbridge aggregator');
1783
1276
  this.log.info('Matter node storage started');
1784
- // Backup matter storage since it is created/opened correctly
1785
1277
  await this.backupMatterStorage(path.join(this.matterbridgeDirectory, this.matterStorageName), path.join(this.matterbridgeDirectory, this.matterStorageName + '.backup'));
1786
1278
  }
1787
- /**
1788
- * Makes a backup copy of the specified matter storage directory.
1789
- *
1790
- * @param storageName - The name of the storage directory to be backed up.
1791
- * @param backupName - The name of the backup directory to be created.
1792
- * @returns {Promise<void>} A promise that resolves when the has been done.
1793
- */
1794
1279
  async backupMatterStorage(storageName, backupName) {
1795
1280
  this.log.info('Creating matter node storage backup...');
1796
1281
  await copyDirectory(storageName, backupName);
1797
1282
  this.log.info('Created matter node storage backup');
1798
1283
  }
1799
- /**
1800
- * Stops the matter storage.
1801
- * @returns {Promise<void>} A promise that resolves when the storage is stopped.
1802
- */
1803
1284
  async stopMatterStorage() {
1804
1285
  this.log.info('Closing matter node storage...');
1805
1286
  this.matterStorageManager?.close();
@@ -1808,19 +1289,6 @@ export class Matterbridge extends EventEmitter {
1808
1289
  this.matterbridgeContext = undefined;
1809
1290
  this.log.info('Matter node storage closed');
1810
1291
  }
1811
- /**
1812
- * Creates a server node storage context.
1813
- *
1814
- * @param {string} pluginName - The name of the plugin.
1815
- * @param {string} deviceName - The name of the device.
1816
- * @param {DeviceTypeId} deviceType - The device type of the device.
1817
- * @param {number} vendorId - The vendor ID.
1818
- * @param {string} vendorName - The vendor name.
1819
- * @param {number} productId - The product ID.
1820
- * @param {string} productName - The product name.
1821
- * @param {string} [serialNumber] - The serial number of the device (optional).
1822
- * @returns {Promise<StorageContext>} The storage context for the commissioning server.
1823
- */
1824
1292
  async createServerNodeContext(pluginName, deviceName, deviceType, vendorId, vendorName, productId, productName, serialNumber) {
1825
1293
  if (!this.matterStorageService)
1826
1294
  throw new Error('No storage service initialized');
@@ -1853,15 +1321,6 @@ export class Matterbridge extends EventEmitter {
1853
1321
  this.log.debug(`- hardwareVersion: ${await storageContext.get('hardwareVersion')} hardwareVersionString: ${await storageContext.get('hardwareVersionString')}`);
1854
1322
  return storageContext;
1855
1323
  }
1856
- /**
1857
- * Creates a server node.
1858
- *
1859
- * @param {StorageContext} storageContext - The storage context for the server node.
1860
- * @param {number} [port=5540] - The port number for the server node. Defaults to 5540.
1861
- * @param {number} [passcode=20242025] - The passcode for the server node. Defaults to 20242025.
1862
- * @param {number} [discriminator=3850] - The discriminator for the server node. Defaults to 3850.
1863
- * @returns {Promise<ServerNode<ServerNode.RootEndpoint>>} A promise that resolves to the created server node.
1864
- */
1865
1324
  async createServerNode(storageContext, port = 5540, passcode = 20242025, discriminator = 3850) {
1866
1325
  const storeId = await storageContext.get('storeId');
1867
1326
  this.log.notice(`Creating server node for ${storeId} on port ${port} with passcode ${passcode} and discriminator ${discriminator}...`);
@@ -1871,33 +1330,21 @@ export class Matterbridge extends EventEmitter {
1871
1330
  this.log.debug(`- uniqueId: ${await storageContext.get('uniqueId')}`);
1872
1331
  this.log.debug(`- softwareVersion: ${await storageContext.get('softwareVersion')} softwareVersionString: ${await storageContext.get('softwareVersionString')}`);
1873
1332
  this.log.debug(`- hardwareVersion: ${await storageContext.get('hardwareVersion')} hardwareVersionString: ${await storageContext.get('hardwareVersionString')}`);
1874
- /**
1875
- * Create a Matter ServerNode, which contains the Root Endpoint and all relevant data and configuration
1876
- */
1877
1333
  const serverNode = await ServerNode.create({
1878
- // Required: Give the Node a unique ID which is used to store the state of this node
1879
1334
  id: storeId,
1880
- // Provide Network relevant configuration like the port
1881
- // Optional when operating only one device on a host, Default port is 5540
1882
1335
  network: {
1883
1336
  listeningAddressIpv4: this.ipv4address,
1884
1337
  listeningAddressIpv6: this.ipv6address,
1885
1338
  port,
1886
1339
  },
1887
- // Provide Commissioning relevant settings
1888
- // Optional for development/testing purposes
1889
1340
  commissioning: {
1890
1341
  passcode,
1891
1342
  discriminator,
1892
1343
  },
1893
- // Provide Node announcement settings
1894
- // Optional: If Ommitted some development defaults are used
1895
1344
  productDescription: {
1896
1345
  name: await storageContext.get('deviceName'),
1897
1346
  deviceType: DeviceTypeId(await storageContext.get('deviceType')),
1898
1347
  },
1899
- // Provide defaults for the BasicInformation cluster on the Root endpoint
1900
- // Optional: If Omitted some development defaults are used
1901
1348
  basicInformation: {
1902
1349
  vendorId: VendorId(await storageContext.get('vendorId')),
1903
1350
  vendorName: await storageContext.get('vendorName'),
@@ -1914,13 +1361,12 @@ export class Matterbridge extends EventEmitter {
1914
1361
  },
1915
1362
  });
1916
1363
  const sanitizeFabrics = (fabrics, resetSessions = false) => {
1917
- // New type of fabric information: Record<FabricIndex, ExposedFabricInformation>
1918
1364
  const sanitizedFabrics = this.sanitizeFabricInformations(Array.from(Object.values(fabrics)));
1919
1365
  this.log.info(`Fabrics: ${debugStringify(sanitizedFabrics)}`);
1920
1366
  if (this.bridgeMode === 'bridge') {
1921
1367
  this.matterbridgeFabricInformations = sanitizedFabrics;
1922
1368
  if (resetSessions)
1923
- this.matterbridgeSessionInformations = undefined; // Changed cause Invoke Matterbridge.operationalCredentials.updateFabricLabel is sent after the session is created
1369
+ this.matterbridgeSessionInformations = undefined;
1924
1370
  this.matterbridgePaired = true;
1925
1371
  }
1926
1372
  if (this.bridgeMode === 'childbridge') {
@@ -1928,19 +1374,13 @@ export class Matterbridge extends EventEmitter {
1928
1374
  if (plugin) {
1929
1375
  plugin.fabricInformations = sanitizedFabrics;
1930
1376
  if (resetSessions)
1931
- plugin.sessionInformations = undefined; // Changed cause Invoke Matterbridge.operationalCredentials.updateFabricLabel is sent after the session is created
1377
+ plugin.sessionInformations = undefined;
1932
1378
  plugin.paired = true;
1933
1379
  }
1934
1380
  }
1935
1381
  };
1936
- /**
1937
- * This event is triggered when the device is initially commissioned successfully.
1938
- * This means: It is added to the first fabric.
1939
- */
1940
1382
  serverNode.lifecycle.commissioned.on(() => this.log.notice(`Server node for ${storeId} was initially commissioned successfully!`));
1941
- /** This event is triggered when all fabrics are removed from the device, usually it also does a factory reset then. */
1942
1383
  serverNode.lifecycle.decommissioned.on(() => this.log.notice(`Server node for ${storeId} was fully decommissioned successfully!`));
1943
- /** This event is triggered when the device went online. This means that it is discoverable in the network. */
1944
1384
  serverNode.lifecycle.online.on(async () => {
1945
1385
  this.log.notice(`Server node for ${storeId} is online`);
1946
1386
  if (!serverNode.lifecycle.isCommissioned) {
@@ -1986,7 +1426,6 @@ export class Matterbridge extends EventEmitter {
1986
1426
  }
1987
1427
  this.frontend.wssSendRefreshRequired();
1988
1428
  });
1989
- /** This event is triggered when the device went offline. it is not longer discoverable or connectable in the network. */
1990
1429
  serverNode.lifecycle.offline.on(() => {
1991
1430
  this.log.notice(`Server node for ${storeId} is offline`);
1992
1431
  if (this.bridgeMode === 'bridge') {
@@ -2008,10 +1447,6 @@ export class Matterbridge extends EventEmitter {
2008
1447
  }
2009
1448
  this.frontend.wssSendRefreshRequired();
2010
1449
  });
2011
- /**
2012
- * This event is triggered when a fabric is added, removed or updated on the device. Use this if more granular
2013
- * information is needed.
2014
- */
2015
1450
  serverNode.events.commissioning.fabricsChanged.on((fabricIndex, fabricAction) => {
2016
1451
  let action = '';
2017
1452
  switch (fabricAction) {
@@ -2045,24 +1480,16 @@ export class Matterbridge extends EventEmitter {
2045
1480
  }
2046
1481
  }
2047
1482
  };
2048
- /**
2049
- * This event is triggered when an operative new session was opened by a Controller.
2050
- * It is not triggered for the initial commissioning process, just afterwards for real connections.
2051
- */
2052
1483
  serverNode.events.sessions.opened.on((session) => {
2053
1484
  this.log.notice(`Session opened on server node for ${storeId}: ${debugStringify(session)}`);
2054
1485
  sanitizeSessions(Object.values(serverNode.state.sessions.sessions));
2055
1486
  this.frontend.wssSendRefreshRequired();
2056
1487
  });
2057
- /**
2058
- * This event is triggered when an operative session is closed by a Controller or because the Device goes offline.
2059
- */
2060
1488
  serverNode.events.sessions.closed.on((session) => {
2061
1489
  this.log.notice(`Session closed on server node for ${storeId}: ${debugStringify(session)}`);
2062
1490
  sanitizeSessions(Object.values(serverNode.state.sessions.sessions));
2063
1491
  this.frontend.wssSendRefreshRequired();
2064
1492
  });
2065
- /** This event is triggered when a subscription gets added or removed on an operative session. */
2066
1493
  serverNode.events.sessions.subscriptionsChanged.on((session) => {
2067
1494
  this.log.notice(`Session subscriptions changed on server node for ${storeId}: ${debugStringify(session)}`);
2068
1495
  sanitizeSessions(Object.values(serverNode.state.sessions.sessions));
@@ -2071,61 +1498,38 @@ export class Matterbridge extends EventEmitter {
2071
1498
  this.log.info(`Created server node for ${storeId}`);
2072
1499
  return serverNode;
2073
1500
  }
2074
- /**
2075
- * Starts the specified server node.
2076
- *
2077
- * @param {ServerNode} [matterServerNode] - The server node to start.
2078
- * @returns {Promise<void>} A promise that resolves when the server node has started.
2079
- */
2080
1501
  async startServerNode(matterServerNode) {
2081
1502
  if (!matterServerNode)
2082
1503
  return;
2083
1504
  this.log.notice(`Starting ${matterServerNode.id} server node`);
2084
1505
  await matterServerNode.start();
2085
1506
  }
2086
- /**
2087
- * Stops the specified server node.
2088
- *
2089
- * @param {ServerNode} matterServerNode - The server node to stop.
2090
- * @returns {Promise<void>} A promise that resolves when the server node has stopped.
2091
- */
2092
1507
  async stopServerNode(matterServerNode) {
2093
1508
  if (!matterServerNode)
2094
1509
  return;
2095
1510
  this.log.notice(`Closing ${matterServerNode.id} server node`);
2096
- /*
2097
- await matterServerNode.close();
2098
- this.log.info(`Closed ${matterServerNode.id} server node`);
2099
- */
2100
- // Helper function to add a timeout to a promise
2101
1511
  const withTimeout = (promise, ms) => {
2102
1512
  return new Promise((resolve, reject) => {
2103
1513
  const timer = setTimeout(() => reject(new Error('Operation timed out')), ms);
2104
1514
  promise
2105
1515
  .then((result) => {
2106
- clearTimeout(timer); // Prevent memory leak
1516
+ clearTimeout(timer);
2107
1517
  resolve(result);
2108
1518
  })
2109
1519
  .catch((error) => {
2110
- clearTimeout(timer); // Ensure timeout does not fire if promise rejects first
1520
+ clearTimeout(timer);
2111
1521
  reject(error);
2112
1522
  });
2113
1523
  });
2114
1524
  };
2115
1525
  try {
2116
- await withTimeout(matterServerNode.close(), 5000); // 5 seconds timeout
1526
+ await withTimeout(matterServerNode.close(), 5000);
2117
1527
  this.log.info(`Closed ${matterServerNode.id} server node`);
2118
1528
  }
2119
1529
  catch (error) {
2120
1530
  this.log.error(`Failed to close ${matterServerNode.id} server node: ${error instanceof Error ? error.message : error}`);
2121
1531
  }
2122
1532
  }
2123
- /**
2124
- * Advertises the specified server node if it is commissioned.
2125
- *
2126
- * @param {ServerNode} [matterServerNode] - The server node to advertise.
2127
- * @returns {Promise<{ qrPairingCode: string, manualPairingCode: string } | undefined>} A promise that resolves to the pairing codes if the server node is advertised, or undefined if not.
2128
- */
2129
1533
  async advertiseServerNode(matterServerNode) {
2130
1534
  if (matterServerNode && matterServerNode.lifecycle.isCommissioned) {
2131
1535
  await matterServerNode.env.get(DeviceCommissioner)?.allowBasicCommissioning();
@@ -2135,32 +1539,17 @@ export class Matterbridge extends EventEmitter {
2135
1539
  }
2136
1540
  return undefined;
2137
1541
  }
2138
- /**
2139
- * Creates an aggregator node with the specified storage context.
2140
- *
2141
- * @param {StorageContext} storageContext - The storage context for the aggregator node.
2142
- * @returns {Promise<EndpointNode<AggregatorEndpoint>>} A promise that resolves to the created aggregator node.
2143
- */
2144
1542
  async createAggregatorNode(storageContext) {
2145
1543
  this.log.notice(`Creating ${await storageContext.get('storeId')} aggregator `);
2146
1544
  const aggregatorNode = new EndpointNode(AggregatorEndpoint, { id: `${await storageContext.get('storeId')}` });
2147
1545
  return aggregatorNode;
2148
1546
  }
2149
- /**
2150
- * Adds a MatterbridgeEndpoint to the specified plugin.
2151
- *
2152
- * @param {string} pluginName - The name of the plugin.
2153
- * @param {MatterbridgeEndpoint} device - The device to add as a bridged endpoint.
2154
- * @returns {Promise<void>} A promise that resolves when the bridged endpoint has been added.
2155
- */
2156
1547
  async addBridgedEndpoint(pluginName, device) {
2157
- // Check if the plugin is registered
2158
1548
  const plugin = this.plugins.get(pluginName);
2159
1549
  if (!plugin) {
2160
1550
  this.log.error(`Error adding bridged endpoint ${dev}${device.deviceName}${er} (${zb}${device.id}${er}) plugin ${plg}${pluginName}${er} not found`);
2161
1551
  return;
2162
1552
  }
2163
- // Register and add the device to the matterbridge aggregator node
2164
1553
  if (this.bridgeMode === 'bridge') {
2165
1554
  this.log.debug(`Adding bridged endpoint ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} to Matterbridge aggregator node`);
2166
1555
  if (!this.aggregatorNode)
@@ -2183,26 +1572,16 @@ export class Matterbridge extends EventEmitter {
2183
1572
  plugin.registeredDevices++;
2184
1573
  if (plugin.addedDevices !== undefined)
2185
1574
  plugin.addedDevices++;
2186
- // Add the device to the DeviceManager
2187
1575
  this.devices.set(device);
2188
1576
  this.log.info(`Added and registered bridged endpoint (${plugin.registeredDevices}/${plugin.addedDevices}) ${dev}${device.deviceName}${nf} (${dev}${device.id}${nf}) for plugin ${plg}${pluginName}${nf}`);
2189
1577
  }
2190
- /**
2191
- * Removes a MatterbridgeEndpoint from the specified plugin.
2192
- *
2193
- * @param {string} pluginName - The name of the plugin.
2194
- * @param {MatterbridgeEndpoint} device - The device to remove as a bridged endpoint.
2195
- * @returns {Promise<void>} A promise that resolves when the bridged endpoint has been removed.
2196
- */
2197
1578
  async removeBridgedEndpoint(pluginName, device) {
2198
1579
  this.log.debug(`Removing bridged endpoint ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} (${zb}${device.name}${db}) for plugin ${plg}${pluginName}${db}`);
2199
- // Check if the plugin is registered
2200
1580
  const plugin = this.plugins.get(pluginName);
2201
1581
  if (!plugin) {
2202
1582
  this.log.error(`Error removing bridged endpoint ${dev}${device.deviceName}${er} (${zb}${device.name}${er}) for plugin ${plg}${pluginName}${er}: plugin not found`);
2203
1583
  return;
2204
1584
  }
2205
- // Register and add the device to the matterbridge aggregator node
2206
1585
  if (this.bridgeMode === 'bridge') {
2207
1586
  if (!this.aggregatorNode) {
2208
1587
  this.log.error(`Error removing bridged endpoint ${dev}${device.deviceName}${er} (${zb}${device.name}${er}) for plugin ${plg}${pluginName}${er}: aggregator node not found`);
@@ -2217,7 +1596,6 @@ export class Matterbridge extends EventEmitter {
2217
1596
  }
2218
1597
  else if (this.bridgeMode === 'childbridge') {
2219
1598
  if (plugin.type === 'AccessoryPlatform') {
2220
- // Nothing to do here since the server node has no aggregator node but only the device itself
2221
1599
  }
2222
1600
  else if (plugin.type === 'DynamicPlatform') {
2223
1601
  if (!plugin.aggregatorNode) {
@@ -2231,7 +1609,6 @@ export class Matterbridge extends EventEmitter {
2231
1609
  plugin.registeredDevices--;
2232
1610
  if (plugin.addedDevices !== undefined)
2233
1611
  plugin.addedDevices--;
2234
- // Close the server node TODO check if this is correct
2235
1612
  if (plugin.registeredDevices === 0 && plugin.addedDevices === 0) {
2236
1613
  if (plugin.serverNode) {
2237
1614
  await this.stopServerNode(plugin.serverNode);
@@ -2242,27 +1619,14 @@ export class Matterbridge extends EventEmitter {
2242
1619
  }
2243
1620
  }
2244
1621
  }
2245
- // Remove the device from the DeviceManager
2246
1622
  this.devices.remove(device);
2247
1623
  }
2248
- /**
2249
- * Removes all bridged endpoints from the specified plugin.
2250
- *
2251
- * @param {string} pluginName - The name of the plugin.
2252
- * @returns {Promise<void>} A promise that resolves when all bridged endpoints have been removed.
2253
- */
2254
1624
  async removeAllBridgedEndpoints(pluginName) {
2255
1625
  this.log.debug(`Removing all bridged endpoints for plugin ${plg}${pluginName}${db}`);
2256
1626
  for (const device of this.devices.array().filter((device) => device.plugin === pluginName)) {
2257
1627
  await this.removeBridgedEndpoint(pluginName, device);
2258
1628
  }
2259
1629
  }
2260
- /**
2261
- * Sanitizes the fabric information by converting bigint properties to strings because `res.json` doesn't support bigint.
2262
- *
2263
- * @param {ExposedFabricInformation[]} fabricInfo - The array of exposed fabric information objects.
2264
- * @returns {SanitizedExposedFabricInformation[]} An array of sanitized exposed fabric information objects.
2265
- */
2266
1630
  sanitizeFabricInformations(fabricInfo) {
2267
1631
  return fabricInfo.map((info) => {
2268
1632
  return {
@@ -2276,12 +1640,6 @@ export class Matterbridge extends EventEmitter {
2276
1640
  };
2277
1641
  });
2278
1642
  }
2279
- /**
2280
- * Sanitizes the session information by converting bigint properties to strings because `res.json` doesn't support bigint.
2281
- *
2282
- * @param {SessionInformation[]} sessionInfo - The array of session information objects.
2283
- * @returns {SanitizedSessionInformation[]} An array of sanitized session information objects.
2284
- */
2285
1643
  sanitizeSessionInformation(sessionInfo) {
2286
1644
  return sessionInfo
2287
1645
  .filter((session) => session.isPeerActive)
@@ -2309,51 +1667,11 @@ export class Matterbridge extends EventEmitter {
2309
1667
  };
2310
1668
  });
2311
1669
  }
2312
- /**
2313
- * Sets the reachability of a matter server node and trigger ReachableChanged event.
2314
- *
2315
- * @param {ServerNode<ServerNode.RootEndpoint>} serverNode - The commissioning server to set the reachability for.
2316
- * @param {boolean} reachable - The new reachability status.
2317
- */
2318
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
2319
1670
  setServerNodeReachability(serverNode, reachable) {
2320
- /*
2321
- const basicInformationCluster = commissioningServer?.getRootClusterServer(BasicInformationCluster);
2322
- if (basicInformationCluster && basicInformationCluster.attributes.reachable !== undefined) basicInformationCluster.setReachableAttribute(reachable);
2323
- if (basicInformationCluster && basicInformationCluster.triggerReachableChangedEvent) basicInformationCluster.triggerReachableChangedEvent({ reachableNewValue: reachable });
2324
- */
2325
1671
  }
2326
- /**
2327
- * Sets the reachability of the specified matter aggregator and its bridged devices and trigger.
2328
- * @param {EndpointNode<AggregatorEndpoint>} aggregatorNode - The matter aggregator to set the reachability for.
2329
- * @param {boolean} reachable - A boolean indicating the reachability status to set.
2330
- */
2331
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
2332
1672
  setAggregatorReachability(aggregatorNode, reachable) {
2333
- /*
2334
- const basicInformationCluster = matterAggregator.getClusterServer(BasicInformationCluster);
2335
- if (basicInformationCluster && basicInformationCluster.attributes.reachable !== undefined) basicInformationCluster.setReachableAttribute(reachable);
2336
- if (basicInformationCluster && basicInformationCluster.triggerReachableChangedEvent) basicInformationCluster.triggerReachableChangedEvent({ reachableNewValue: reachable });
2337
- matterAggregator.getBridgedDevices().forEach((device) => {
2338
- this.log.debug(`Setting reachability to true for bridged device: ${dev}${device.name}${nf}`);
2339
- device.getClusterServer(BridgedDeviceBasicInformationCluster)?.setReachableAttribute(reachable);
2340
- device.getClusterServer(BridgedDeviceBasicInformationCluster)?.triggerReachableChangedEvent({ reachableNewValue: reachable });
2341
- });
2342
- */
2343
1673
  }
2344
- /**
2345
- * Sets the reachability of a device and trigger.
2346
- *
2347
- * @param {MatterbridgeEndpoint} device - The device to set the reachability for.
2348
- * @param {boolean} reachable - The new reachability status of the device.
2349
- */
2350
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
2351
1674
  setDeviceReachability(device, reachable) {
2352
- /*
2353
- const basicInformationCluster = device.getClusterServer(BasicInformationCluster);
2354
- if (basicInformationCluster && basicInformationCluster.attributes.reachable !== undefined) basicInformationCluster.setReachableAttribute(reachable);
2355
- if (basicInformationCluster && basicInformationCluster.triggerReachableChangedEvent) basicInformationCluster.triggerReachableChangedEvent({ reachableNewValue: reachable });
2356
- */
2357
1675
  }
2358
1676
  getVendorIdName = (vendorId) => {
2359
1677
  if (!vendorId)
@@ -2396,36 +1714,13 @@ export class Matterbridge extends EventEmitter {
2396
1714
  }
2397
1715
  return vendorName;
2398
1716
  };
2399
- /**
2400
- * Spawns a child process with the given command and arguments.
2401
- * @param {string} command - The command to execute.
2402
- * @param {string[]} args - The arguments to pass to the command (default: []).
2403
- * @returns {Promise<boolean>} A promise that resolves when the child process exits successfully, or rejects if there is an error.
2404
- */
2405
1717
  async spawnCommand(command, args = []) {
2406
- /*
2407
- npm > npm.cmd on windows
2408
- cmd.exe ['dir'] on windows
2409
- await this.spawnCommand('npm', ['install', '-g', 'matterbridge']);
2410
- process.on('unhandledRejection', (reason, promise) => {
2411
- this.log.error('Unhandled Rejection at:', promise, 'reason:', reason);
2412
- });
2413
-
2414
- spawn - [14:27:21.125] [Matterbridge:spawn]: changed 38 packages in 4s
2415
- spawn - [14:27:21.125] [Matterbridge:spawn]: 10 packages are looking for funding run `npm fund` for details
2416
- debug - [14:27:21.131] [Matterbridge]: Child process exited with code 0 and signal null
2417
- debug - [14:27:21.131] [Matterbridge]: Child process stdio streams have closed with code 0
2418
- */
2419
1718
  const cmdLine = command + ' ' + args.join(' ');
2420
1719
  if (process.platform === 'win32' && command === 'npm') {
2421
- // Must be spawn('cmd.exe', ['/c', 'npm -g install <package>']);
2422
1720
  const argstring = 'npm ' + args.join(' ');
2423
1721
  args.splice(0, args.length, '/c', argstring);
2424
1722
  command = 'cmd.exe';
2425
1723
  }
2426
- // Decide when using sudo on linux
2427
- // When you need sudo: Spawn stderr: npm error Error: EACCES: permission denied
2428
- // When you don't need sudo: Failed to start child process "npm install -g matterbridge-eve-door": spawn sudo ENOENT
2429
1724
  if (hasParameter('sudo') || (process.platform === 'linux' && command === 'npm' && !hasParameter('docker') && !hasParameter('nosudo'))) {
2430
1725
  args.unshift(command);
2431
1726
  command = 'sudo';
@@ -2484,4 +1779,3 @@ export class Matterbridge extends EventEmitter {
2484
1779
  });
2485
1780
  }
2486
1781
  }
2487
- //# sourceMappingURL=matterbridge.js.map