matterbridge 2.1.2 → 2.1.3-dev.1

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 +24 -10
  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 -231
  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 +57 -741
  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 +6 -690
  21. package/dist/matterbridgeEndpointHelpers.js +0 -96
  22. package/dist/matterbridgePlatform.js +3 -111
  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 +7 -251
  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 -2262
  89. package/dist/matterbridgeEndpointHelpers.d.ts.map +0 -1
  90. package/dist/matterbridgeEndpointHelpers.js.map +0 -1
  91. package/dist/matterbridgePlatform.d.ts +0 -152
  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 -221
  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
10
  import { logInterfaces, copyDirectory, getParameter, getIntParameter, hasParameter } 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, 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,79 +140,51 @@ 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
144
  await this.cleanup('destroying instance...', false);
205
145
  await new Promise((resolve) => {
206
146
  setTimeout(resolve, 1000);
207
147
  });
208
148
  }
209
- /**
210
- * Initializes the Matterbridge application.
211
- *
212
- * @remarks
213
- * This method performs the necessary setup and initialization steps for the Matterbridge application.
214
- * It displays the help information if the 'help' parameter is provided, sets up the logger, checks the
215
- * node version, registers signal handlers, initializes storage, and parses the command line.
216
- *
217
- * @returns A Promise that resolves when the initialization is complete.
218
- */
219
149
  async initialize() {
220
- // Set the restart mode
221
150
  if (hasParameter('service'))
222
151
  this.restartMode = 'service';
223
152
  if (hasParameter('docker'))
224
153
  this.restartMode = 'docker';
225
- // Set the matterbridge directory
226
154
  this.homeDirectory = getParameter('homedir') ?? os.homedir();
227
155
  this.matterbridgeDirectory = path.join(this.homeDirectory, '.matterbridge');
228
- // Setup the matter environment
229
156
  this.environment.vars.set('log.level', MatterLogLevel.INFO);
230
157
  this.environment.vars.set('log.format', MatterLogFormat.ANSI);
231
158
  this.environment.vars.set('path.root', path.join(this.matterbridgeDirectory, this.matterStorageName));
232
159
  this.environment.vars.set('runtime.signals', false);
233
160
  this.environment.vars.set('runtime.exitcode', false);
234
- // Create the matterbridge logger
235
- this.log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: hasParameter('debug') ? "debug" /* LogLevel.DEBUG */ : "info" /* LogLevel.INFO */ });
236
- // Register process handlers
161
+ this.log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4, logLevel: hasParameter('debug') ? "debug" : "info" });
237
162
  this.registerProcessHandlers();
238
- // Initialize nodeStorage and nodeContext
239
163
  try {
240
164
  this.log.debug(`Creating node storage manager: ${CYAN}${this.nodeStorageName}${db}`);
241
165
  this.nodeStorage = new NodeStorageManager({ dir: path.join(this.matterbridgeDirectory, this.nodeStorageName), writeQueue: false, expiredInterval: undefined, logging: false });
242
166
  this.log.debug('Creating node storage context for matterbridge');
243
167
  this.nodeContext = await this.nodeStorage.createStorage('matterbridge');
244
- // TODO: Remove this code when node-persist-manager is updated
245
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
246
168
  const keys = (await this.nodeStorage?.storage.keys());
247
169
  for (const key of keys) {
248
170
  this.log.debug(`Checking node storage manager key: ${CYAN}${key}${db}`);
249
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
250
171
  await this.nodeStorage?.storage.get(key);
251
172
  }
252
173
  const storages = await this.nodeStorage.getStorageNames();
253
174
  for (const storage of storages) {
254
175
  this.log.debug(`Checking storage: ${CYAN}${storage}${db}`);
255
176
  const nodeContext = await this.nodeStorage?.createStorage(storage);
256
- // TODO: Remove this code when node-persist-manager is updated
257
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
258
177
  const keys = (await nodeContext?.storage.keys());
259
178
  keys.forEach(async (key) => {
260
179
  this.log.debug(`Checking key: ${CYAN}${storage}:${key}${db}`);
261
180
  await nodeContext?.get(key);
262
181
  });
263
182
  }
264
- // Creating a backup of the node storage since it is not corrupted
265
183
  this.log.debug('Creating node storage backup...');
266
184
  await copyDirectory(path.join(this.matterbridgeDirectory, this.nodeStorageName), path.join(this.matterbridgeDirectory, this.nodeStorageName + '.backup'));
267
185
  this.log.debug('Created node storage backup');
268
186
  }
269
187
  catch (error) {
270
- // Restoring the backup of the node storage since it is corrupted
271
188
  this.log.error(`Error creating node storage manager and context: ${error instanceof Error ? error.message : error}`);
272
189
  if (hasParameter('norestore')) {
273
190
  this.log.fatal(`The matterbridge node storage is corrupted. Parameter -norestore found: exiting...`);
@@ -282,51 +199,45 @@ export class Matterbridge extends EventEmitter {
282
199
  this.log.fatal('Fatal error creating node storage manager and context for matterbridge');
283
200
  throw new Error('Fatal error creating node storage manager and context for matterbridge');
284
201
  }
285
- // Set the first port to use for the commissioning server (will be incremented in childbridge mode)
286
202
  this.port = getIntParameter('port') ?? (await this.nodeContext.get('matterport', 5540)) ?? 5540;
287
- // Set the first passcode to use for the commissioning server (will be incremented in childbridge mode)
288
203
  this.passcode = getIntParameter('passcode') ?? (await this.nodeContext.get('matterpasscode')) ?? PaseClient.generateRandomPasscode();
289
- // Set the first discriminator to use for the commissioning server (will be incremented in childbridge mode)
290
204
  this.discriminator = getIntParameter('discriminator') ?? (await this.nodeContext.get('matterdiscriminator')) ?? PaseClient.generateRandomDiscriminator();
291
205
  this.log.debug(`Initializing commissioning server for Matterbridge... on port ${this.port} with passcode ${this.passcode} and discriminator ${this.discriminator}`);
292
- // Set matterbridge logger level (context: matterbridgeLogLevel)
293
206
  if (hasParameter('logger')) {
294
207
  const level = getParameter('logger');
295
208
  if (level === 'debug') {
296
- this.log.logLevel = "debug" /* LogLevel.DEBUG */;
209
+ this.log.logLevel = "debug";
297
210
  }
298
211
  else if (level === 'info') {
299
- this.log.logLevel = "info" /* LogLevel.INFO */;
212
+ this.log.logLevel = "info";
300
213
  }
301
214
  else if (level === 'notice') {
302
- this.log.logLevel = "notice" /* LogLevel.NOTICE */;
215
+ this.log.logLevel = "notice";
303
216
  }
304
217
  else if (level === 'warn') {
305
- this.log.logLevel = "warn" /* LogLevel.WARN */;
218
+ this.log.logLevel = "warn";
306
219
  }
307
220
  else if (level === 'error') {
308
- this.log.logLevel = "error" /* LogLevel.ERROR */;
221
+ this.log.logLevel = "error";
309
222
  }
310
223
  else if (level === 'fatal') {
311
- this.log.logLevel = "fatal" /* LogLevel.FATAL */;
224
+ this.log.logLevel = "fatal";
312
225
  }
313
226
  else {
314
227
  this.log.warn(`Invalid matterbridge logger level: ${level}. Using default level "info".`);
315
- this.log.logLevel = "info" /* LogLevel.INFO */;
228
+ this.log.logLevel = "info";
316
229
  }
317
230
  }
318
231
  else {
319
- this.log.logLevel = await this.nodeContext.get('matterbridgeLogLevel', "info" /* LogLevel.INFO */);
232
+ this.log.logLevel = await this.nodeContext.get('matterbridgeLogLevel', "info");
320
233
  }
321
234
  MatterbridgeEndpoint.logLevel = this.log.logLevel;
322
- // Create the file logger for matterbridge (context: matterbridgeFileLog)
323
235
  if (hasParameter('filelogger') || (await this.nodeContext.get('matterbridgeFileLog', false))) {
324
236
  AnsiLogger.setGlobalLogfile(path.join(this.matterbridgeDirectory, this.matterbrideLoggerFile), this.log.logLevel, true);
325
237
  this.matterbridgeInformation.fileLogger = true;
326
238
  }
327
239
  this.log.notice('Matterbridge is starting...');
328
240
  this.log.debug(`Matterbridge logLevel: ${this.log.logLevel} fileLoger: ${this.matterbridgeInformation.fileLogger}.`);
329
- // Set matter.js logger level, format and logger (context: matterLogLevel)
330
241
  if (hasParameter('matterlogger')) {
331
242
  const level = getParameter('matterlogger');
332
243
  if (level === 'debug') {
@@ -357,7 +268,6 @@ export class Matterbridge extends EventEmitter {
357
268
  }
358
269
  Logger.format = MatterLogFormat.ANSI;
359
270
  Logger.setLogger('default', this.createMatterLogger());
360
- // Create the file logger for matter.js (context: matterFileLog)
361
271
  if (hasParameter('matterfilelogger') || (await this.nodeContext.get('matterFileLog', false))) {
362
272
  this.matterbridgeInformation.matterFileLogger = true;
363
273
  Logger.addLogger('matterfilelogger', await this.createMatterFileLogger(path.join(this.matterbridgeDirectory, this.matterLoggerFile), true), {
@@ -366,7 +276,6 @@ export class Matterbridge extends EventEmitter {
366
276
  });
367
277
  }
368
278
  this.log.debug(`Matter logLevel: ${Logger.defaultLogLevel} fileLoger: ${this.matterbridgeInformation.matterFileLogger}.`);
369
- // Set the interface to use for matter server node mdnsInterface
370
279
  if (hasParameter('mdnsinterface')) {
371
280
  this.mdnsInterface = getParameter('mdnsinterface');
372
281
  }
@@ -375,7 +284,6 @@ export class Matterbridge extends EventEmitter {
375
284
  if (this.mdnsInterface === '')
376
285
  this.mdnsInterface = undefined;
377
286
  }
378
- // Validate mdnsInterface
379
287
  if (this.mdnsInterface) {
380
288
  const networkInterfaces = os.networkInterfaces();
381
289
  const availableInterfaces = Object.keys(networkInterfaces);
@@ -389,7 +297,6 @@ export class Matterbridge extends EventEmitter {
389
297
  }
390
298
  if (this.mdnsInterface)
391
299
  this.environment.vars.set('mdns.networkInterface', this.mdnsInterface);
392
- // Set the listeningAddressIpv4 for the matter commissioning server
393
300
  if (hasParameter('ipv4address')) {
394
301
  this.ipv4address = getParameter('ipv4address');
395
302
  }
@@ -398,7 +305,6 @@ export class Matterbridge extends EventEmitter {
398
305
  if (this.ipv4address === '')
399
306
  this.ipv4address = undefined;
400
307
  }
401
- // Set the listeningAddressIpv6 for the matter commissioning server
402
308
  if (hasParameter('ipv6address')) {
403
309
  this.ipv6address = getParameter('ipv6address');
404
310
  }
@@ -407,19 +313,14 @@ export class Matterbridge extends EventEmitter {
407
313
  if (this.ipv6address === '')
408
314
  this.ipv6address = undefined;
409
315
  }
410
- // Initialize PluginManager
411
316
  this.plugins = new PluginManager(this);
412
317
  await this.plugins.loadFromStorage();
413
318
  this.plugins.logLevel = this.log.logLevel;
414
- // Initialize DeviceManager
415
319
  this.devices = new DeviceManager(this, this.nodeContext);
416
320
  this.devices.logLevel = this.log.logLevel;
417
- // Get the plugins from node storage and create the plugins node storage contexts
418
321
  for (const plugin of this.plugins) {
419
322
  const packageJson = await this.plugins.parse(plugin);
420
323
  if (packageJson === null && !hasParameter('add') && !hasParameter('remove') && !hasParameter('enable') && !hasParameter('disable') && !hasParameter('reset') && !hasParameter('factoryreset')) {
421
- // Try to reinstall the plugin from npm (for Docker pull and external plugins)
422
- // We don't do this when the add and other parameters are set because we shut down the process after adding the plugin
423
324
  this.log.info(`Error parsing plugin ${plg}${plugin.name}${nf}. Trying to reinstall it from npm.`);
424
325
  try {
425
326
  await this.spawnCommand('npm', ['install', '-g', plugin.name, '--omit=dev', '--verbose']);
@@ -441,7 +342,6 @@ export class Matterbridge extends EventEmitter {
441
342
  await plugin.nodeContext.set('description', plugin.description);
442
343
  await plugin.nodeContext.set('author', plugin.author);
443
344
  }
444
- // Log system info and create .matterbridge directory
445
345
  await this.logNodeAndSystemInfo();
446
346
  this.log.notice(`Matterbridge version ${this.matterbridgeVersion} ` +
447
347
  `${hasParameter('bridge') || (!hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'bridge') ? 'mode bridge ' : ''}` +
@@ -449,7 +349,6 @@ export class Matterbridge extends EventEmitter {
449
349
  `${hasParameter('controller') ? 'mode controller ' : ''}` +
450
350
  `${this.restartMode !== '' ? 'restart mode ' + this.restartMode + ' ' : ''}` +
451
351
  `running on ${this.systemInformation.osType} (v.${this.systemInformation.osRelease}) platform ${this.systemInformation.osPlatform} arch ${this.systemInformation.osArch}`);
452
- // Check node version and throw error
453
352
  const minNodeVersion = 18;
454
353
  const nodeVersion = process.versions.node;
455
354
  const versionMajor = parseInt(nodeVersion.split('.')[0]);
@@ -457,15 +356,9 @@ export class Matterbridge extends EventEmitter {
457
356
  this.log.error(`Node version ${versionMajor} is not supported. Please upgrade to ${minNodeVersion} or above.`);
458
357
  throw new Error(`Node version ${versionMajor} is not supported. Please upgrade to ${minNodeVersion} or above.`);
459
358
  }
460
- // Parse command line
461
359
  await this.parseCommandLine();
462
360
  this.initialized = true;
463
361
  }
464
- /**
465
- * Parses the command line arguments and performs the corresponding actions.
466
- * @private
467
- * @returns {Promise<void>} A promise that resolves when the command line arguments have been processed, or the process exits.
468
- */
469
362
  async parseCommandLine() {
470
363
  if (hasParameter('help')) {
471
364
  this.log.info(`\nUsage: matterbridge [options]\n
@@ -575,7 +468,6 @@ export class Matterbridge extends EventEmitter {
575
468
  await this.shutdownProcessAndFactoryReset();
576
469
  return;
577
470
  }
578
- // Start the matter storage and create the matterbridge context
579
471
  try {
580
472
  await this.startMatterStorage();
581
473
  }
@@ -583,12 +475,10 @@ export class Matterbridge extends EventEmitter {
583
475
  this.log.fatal(`Fatal error creating matter storage: ${error instanceof Error ? error.message : error}`);
584
476
  throw new Error(`Fatal error creating matter storage: ${error instanceof Error ? error.message : error}`);
585
477
  }
586
- // Clear the matterbridge context if the reset parameter is set
587
478
  if (hasParameter('reset') && getParameter('reset') === undefined) {
588
479
  await this.shutdownProcessAndReset();
589
480
  return;
590
481
  }
591
- // Clear matterbridge plugin context if the reset parameter is set
592
482
  if (hasParameter('reset') && getParameter('reset') !== undefined) {
593
483
  this.log.debug(`Reset plugin ${getParameter('reset')}`);
594
484
  const plugin = this.plugins.get(getParameter('reset'));
@@ -610,11 +500,9 @@ export class Matterbridge extends EventEmitter {
610
500
  this.emit('shutdown');
611
501
  return;
612
502
  }
613
- // Initialize frontend
614
503
  if (getIntParameter('frontend') !== 0 || getIntParameter('frontend') === undefined)
615
504
  await this.frontend.start(getIntParameter('frontend'));
616
505
  this.frontend.logLevel = this.log.logLevel;
617
- // Check each 60 minutes the latest versions
618
506
  this.checkUpdateInterval = setInterval(() => {
619
507
  this.getMatterbridgeLatestVersion();
620
508
  for (const plugin of this.plugins) {
@@ -622,24 +510,20 @@ export class Matterbridge extends EventEmitter {
622
510
  }
623
511
  this.frontend.wssSendRefreshRequired();
624
512
  }, 60 * 60 * 1000);
625
- // Start the matterbridge in mode test
626
513
  if (hasParameter('test')) {
627
514
  this.bridgeMode = 'bridge';
628
515
  MatterbridgeEndpoint.bridgeMode = 'bridge';
629
516
  return;
630
517
  }
631
- // Start the matterbridge in mode controller
632
518
  if (hasParameter('controller')) {
633
519
  this.bridgeMode = 'controller';
634
520
  await this.startController();
635
521
  return;
636
522
  }
637
- // Check if the bridge mode is set and start matterbridge in bridge mode if not set
638
523
  if (!hasParameter('bridge') && !hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === '') {
639
524
  this.log.info('Setting default matterbridge start mode to bridge');
640
525
  await this.nodeContext?.set('bridgeMode', 'bridge');
641
526
  }
642
- // Start matterbridge in bridge mode
643
527
  if (hasParameter('bridge') || (!hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'bridge')) {
644
528
  this.bridgeMode = 'bridge';
645
529
  MatterbridgeEndpoint.bridgeMode = 'bridge';
@@ -647,7 +531,6 @@ export class Matterbridge extends EventEmitter {
647
531
  await this.startBridge();
648
532
  return;
649
533
  }
650
- // Start matterbridge in childbridge mode
651
534
  if (hasParameter('childbridge') || (!hasParameter('bridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'childbridge')) {
652
535
  this.bridgeMode = 'childbridge';
653
536
  MatterbridgeEndpoint.bridgeMode = 'childbridge';
@@ -656,28 +539,16 @@ export class Matterbridge extends EventEmitter {
656
539
  return;
657
540
  }
658
541
  }
659
- /**
660
- * Asynchronously loads and starts the registered plugins.
661
- *
662
- * This method is responsible for initializing and staarting all enabled plugins.
663
- * It ensures that each plugin is properly loaded and started before the bridge starts.
664
- *
665
- * @returns {Promise<void>} A promise that resolves when all plugins have been loaded and started.
666
- */
667
542
  async startPlugins() {
668
- // Check, load and start the plugins
669
543
  for (const plugin of this.plugins) {
670
544
  plugin.configJson = await this.plugins.loadConfig(plugin);
671
545
  plugin.schemaJson = await this.plugins.loadSchema(plugin);
672
- // Check if the plugin is available
673
546
  if (!(await this.plugins.resolve(plugin.path))) {
674
547
  this.log.error(`Plugin ${plg}${plugin.name}${er} not found or not validated. Disabling it.`);
675
548
  plugin.enabled = false;
676
549
  plugin.error = true;
677
550
  continue;
678
551
  }
679
- // Check if the plugin has a new version
680
- // this.getPluginLatestVersion(plugin); // No await do it asyncronously
681
552
  if (!plugin.enabled) {
682
553
  this.log.info(`Plugin ${plg}${plugin.name}${nf} not enabled`);
683
554
  continue;
@@ -691,26 +562,20 @@ export class Matterbridge extends EventEmitter {
691
562
  plugin.addedDevices = undefined;
692
563
  plugin.qrPairingCode = undefined;
693
564
  plugin.manualPairingCode = undefined;
694
- this.plugins.load(plugin, true, 'Matterbridge is starting'); // No await do it asyncronously
565
+ this.plugins.load(plugin, true, 'Matterbridge is starting');
695
566
  }
696
567
  this.frontend.wssSendRefreshRequired();
697
568
  }
698
- /**
699
- * Registers the process handlers for uncaughtException, unhandledRejection, SIGINT and SIGTERM.
700
- * When either of these signals are received, the cleanup method is called with an appropriate message.
701
- */
702
569
  registerProcessHandlers() {
703
570
  this.log.debug(`Registering uncaughtException and unhandledRejection handlers...`);
704
571
  process.removeAllListeners('uncaughtException');
705
572
  process.removeAllListeners('unhandledRejection');
706
573
  this.exceptionHandler = async (error) => {
707
574
  this.log.fatal('Unhandled Exception detected at:', error.stack || error, rs);
708
- // await this.cleanup('Unhandled Exception detected, cleaning up...');
709
575
  };
710
576
  process.on('uncaughtException', this.exceptionHandler);
711
577
  this.rejectionHandler = async (reason, promise) => {
712
578
  this.log.fatal('Unhandled Rejection detected at:', promise, 'reason:', reason instanceof Error ? reason.stack : reason, rs);
713
- // await this.cleanup('Unhandled Rejection detected, cleaning up...');
714
579
  };
715
580
  process.on('unhandledRejection', this.rejectionHandler);
716
581
  this.log.debug(`Registering SIGINT and SIGTERM signal handlers...`);
@@ -723,9 +588,6 @@ export class Matterbridge extends EventEmitter {
723
588
  };
724
589
  process.on('SIGTERM', this.sigtermHandler);
725
590
  }
726
- /**
727
- * Deregisters the process uncaughtException, unhandledRejection, SIGINT and SIGTERM signal handlers.
728
- */
729
591
  deregisterProcesslHandlers() {
730
592
  this.log.debug(`Deregistering uncaughtException and unhandledRejection handlers...`);
731
593
  if (this.exceptionHandler)
@@ -742,17 +604,12 @@ export class Matterbridge extends EventEmitter {
742
604
  process.off('SIGTERM', this.sigtermHandler);
743
605
  this.sigtermHandler = undefined;
744
606
  }
745
- /**
746
- * Logs the node and system information.
747
- */
748
607
  async logNodeAndSystemInfo() {
749
- // IP address information
750
608
  const networkInterfaces = os.networkInterfaces();
751
609
  this.systemInformation.interfaceName = '';
752
610
  this.systemInformation.ipv4Address = '';
753
611
  this.systemInformation.ipv6Address = '';
754
612
  for (const [interfaceName, interfaceDetails] of Object.entries(networkInterfaces)) {
755
- // this.log.debug(`Checking interface: '${interfaceName}' for '${this.mdnsInterface}'`);
756
613
  if (this.mdnsInterface && interfaceName !== this.mdnsInterface)
757
614
  continue;
758
615
  if (!interfaceDetails) {
@@ -778,22 +635,19 @@ export class Matterbridge extends EventEmitter {
778
635
  break;
779
636
  }
780
637
  }
781
- // Node information
782
638
  this.systemInformation.nodeVersion = process.versions.node;
783
639
  const versionMajor = parseInt(this.systemInformation.nodeVersion.split('.')[0]);
784
640
  const versionMinor = parseInt(this.systemInformation.nodeVersion.split('.')[1]);
785
641
  const versionPatch = parseInt(this.systemInformation.nodeVersion.split('.')[2]);
786
- // Host system information
787
642
  this.systemInformation.hostname = os.hostname();
788
643
  this.systemInformation.user = os.userInfo().username;
789
- this.systemInformation.osType = os.type(); // "Windows_NT", "Darwin", etc.
790
- this.systemInformation.osRelease = os.release(); // Kernel version
791
- this.systemInformation.osPlatform = os.platform(); // "win32", "linux", "darwin", etc.
792
- this.systemInformation.osArch = os.arch(); // "x64", "arm", etc.
793
- this.systemInformation.totalMemory = (os.totalmem() / 1024 / 1024 / 1024).toFixed(2) + ' GB'; // Convert to GB
794
- this.systemInformation.freeMemory = (os.freemem() / 1024 / 1024 / 1024).toFixed(2) + ' GB'; // Convert to GB
795
- this.systemInformation.systemUptime = (os.uptime() / 60 / 60).toFixed(2) + ' hours'; // Convert to hours
796
- // Log the system information
644
+ this.systemInformation.osType = os.type();
645
+ this.systemInformation.osRelease = os.release();
646
+ this.systemInformation.osPlatform = os.platform();
647
+ this.systemInformation.osArch = os.arch();
648
+ this.systemInformation.totalMemory = (os.totalmem() / 1024 / 1024 / 1024).toFixed(2) + ' GB';
649
+ this.systemInformation.freeMemory = (os.freemem() / 1024 / 1024 / 1024).toFixed(2) + ' GB';
650
+ this.systemInformation.systemUptime = (os.uptime() / 60 / 60).toFixed(2) + ' hours';
797
651
  this.log.debug('Host System Information:');
798
652
  this.log.debug(`- Hostname: ${this.systemInformation.hostname}`);
799
653
  this.log.debug(`- User: ${this.systemInformation.user}`);
@@ -809,19 +663,15 @@ export class Matterbridge extends EventEmitter {
809
663
  this.log.debug(`- Total Memory: ${this.systemInformation.totalMemory}`);
810
664
  this.log.debug(`- Free Memory: ${this.systemInformation.freeMemory}`);
811
665
  this.log.debug(`- System Uptime: ${this.systemInformation.systemUptime}`);
812
- // Home directory
813
666
  this.homeDirectory = getParameter('homedir') ?? os.homedir();
814
667
  this.matterbridgeInformation.homeDirectory = this.homeDirectory;
815
668
  this.log.debug(`Home Directory: ${this.homeDirectory}`);
816
- // Package root directory
817
669
  const currentFileDirectory = path.dirname(fileURLToPath(import.meta.url));
818
670
  this.rootDirectory = path.resolve(currentFileDirectory, '../');
819
671
  this.matterbridgeInformation.rootDirectory = this.rootDirectory;
820
672
  this.log.debug(`Root Directory: ${this.rootDirectory}`);
821
- // Global node_modules directory
822
673
  if (this.nodeContext)
823
674
  this.globalModulesDirectory = this.matterbridgeInformation.globalModulesDirectory = await this.nodeContext.get('globalModulesDirectory', '');
824
- // First run of Matterbridge so the node storage is empty
825
675
  if (this.globalModulesDirectory === '') {
826
676
  try {
827
677
  this.globalModulesDirectory = await this.getGlobalNodeModules();
@@ -835,20 +685,6 @@ export class Matterbridge extends EventEmitter {
835
685
  }
836
686
  else
837
687
  this.log.debug(`Global node_modules Directory: ${this.globalModulesDirectory}`);
838
- /* removed cause is too expensive for the shelly board and not really needed. Why should it change the globalModulesDirectory?
839
- else {
840
- this.getGlobalNodeModules()
841
- .then(async (globalModulesDirectory) => {
842
- this.globalModulesDirectory = globalModulesDirectory;
843
- this.matterbridgeInformation.globalModulesDirectory = this.globalModulesDirectory;
844
- this.log.debug(`Global node_modules Directory: ${this.globalModulesDirectory}`);
845
- await this.nodeContext?.set<string>('globalModulesDirectory', this.globalModulesDirectory);
846
- })
847
- .catch((error) => {
848
- this.log.error(`Error getting global node_modules directory: ${error}`);
849
- });
850
- }*/
851
- // Create the data directory .matterbridge in the home directory
852
688
  this.matterbridgeDirectory = path.join(this.homeDirectory, '.matterbridge');
853
689
  this.matterbridgeInformation.matterbridgeDirectory = this.matterbridgeDirectory;
854
690
  try {
@@ -872,7 +708,6 @@ export class Matterbridge extends EventEmitter {
872
708
  }
873
709
  }
874
710
  this.log.debug(`Matterbridge Directory: ${this.matterbridgeDirectory}`);
875
- // Create the plugin directory Matterbridge in the home directory
876
711
  this.matterbridgePluginDirectory = path.join(this.homeDirectory, 'Matterbridge');
877
712
  this.matterbridgeInformation.matterbridgePluginDirectory = this.matterbridgePluginDirectory;
878
713
  try {
@@ -896,28 +731,18 @@ export class Matterbridge extends EventEmitter {
896
731
  }
897
732
  }
898
733
  this.log.debug(`Matterbridge Plugin Directory: ${this.matterbridgePluginDirectory}`);
899
- // Matterbridge version
900
734
  const packageJson = JSON.parse(await fs.readFile(path.join(this.rootDirectory, 'package.json'), 'utf-8'));
901
735
  this.matterbridgeVersion = this.matterbridgeLatestVersion = packageJson.version;
902
736
  this.matterbridgeInformation.matterbridgeVersion = this.matterbridgeInformation.matterbridgeLatestVersion = this.matterbridgeVersion;
903
737
  this.log.debug(`Matterbridge Version: ${this.matterbridgeVersion}`);
904
- // Matterbridge latest version
905
738
  if (this.nodeContext)
906
739
  this.matterbridgeLatestVersion = await this.nodeContext.get('matterbridgeLatestVersion', this.matterbridgeVersion);
907
740
  this.log.debug(`Matterbridge Latest Version: ${this.matterbridgeLatestVersion}`);
908
- // this.getMatterbridgeLatestVersion();
909
- // Current working directory
910
741
  const currentDir = process.cwd();
911
742
  this.log.debug(`Current Working Directory: ${currentDir}`);
912
- // Command line arguments (excluding 'node' and the script name)
913
743
  const cmdArgs = process.argv.slice(2).join(' ');
914
744
  this.log.debug(`Command Line Arguments: ${cmdArgs}`);
915
745
  }
916
- /**
917
- * Retrieves the latest version of a package from the npm registry.
918
- * @param packageName - The name of the package.
919
- * @returns A Promise that resolves to the latest version of the package.
920
- */
921
746
  async getLatestVersion(packageName) {
922
747
  return new Promise((resolve, reject) => {
923
748
  this.execRunningCount++;
@@ -932,10 +757,6 @@ export class Matterbridge extends EventEmitter {
932
757
  });
933
758
  });
934
759
  }
935
- /**
936
- * Retrieves the path to the global Node.js modules directory.
937
- * @returns A promise that resolves to the path of the global Node.js modules directory.
938
- */
939
760
  async getGlobalNodeModules() {
940
761
  return new Promise((resolve, reject) => {
941
762
  this.execRunningCount++;
@@ -950,11 +771,6 @@ export class Matterbridge extends EventEmitter {
950
771
  });
951
772
  });
952
773
  }
953
- /**
954
- * Retrieves the latest version of Matterbridge and performs necessary actions based on the version comparison.
955
- * @private
956
- * @returns {Promise<void>} A promise that resolves when the latest version is retrieved and actions are performed.
957
- */
958
774
  async getMatterbridgeLatestVersion() {
959
775
  this.getLatestVersion('matterbridge')
960
776
  .then(async (matterbridgeLatestVersion) => {
@@ -971,19 +787,8 @@ export class Matterbridge extends EventEmitter {
971
787
  })
972
788
  .catch((error) => {
973
789
  this.log.error(`Error getting Matterbridge latest version: ${error.message}`);
974
- // error.stack && this.log.debug(error.stack);
975
790
  });
976
791
  }
977
- /**
978
- * Retrieves the latest version of a plugin and updates the plugin's latestVersion property.
979
- * If the plugin's version is different from the latest version, logs a warning message.
980
- * If the plugin's version is the same as the latest version, logs an info message.
981
- * If there is an error retrieving the latest version, logs an error message.
982
- *
983
- * @private
984
- * @param {RegisteredPlugin} plugin - The plugin for which to retrieve the latest version.
985
- * @returns {Promise<void>} A promise that resolves when the latest version is retrieved and actions are performed.
986
- */
987
792
  async getPluginLatestVersion(plugin) {
988
793
  this.getLatestVersion(plugin.name)
989
794
  .then(async (latestVersion) => {
@@ -995,54 +800,40 @@ export class Matterbridge extends EventEmitter {
995
800
  })
996
801
  .catch((error) => {
997
802
  this.log.error(`Error getting ${plg}${plugin.name}${er} latest version: ${error.message}`);
998
- // error.stack && this.log.debug(error.stack);
999
803
  });
1000
804
  }
1001
- /**
1002
- * Creates a MatterLogger function to show the matter.js log messages in AnsiLogger (for the frontend).
1003
- *
1004
- * @returns {Function} The MatterLogger function.
1005
- */
1006
805
  createMatterLogger() {
1007
- const matterLogger = new AnsiLogger({ logName: 'Matter', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: "debug" /* LogLevel.DEBUG */ });
806
+ const matterLogger = new AnsiLogger({ logName: 'Matter', logTimestampFormat: 4, logLevel: "debug" });
1008
807
  return (_level, formattedLog) => {
1009
808
  const logger = formattedLog.slice(44, 44 + 20).trim();
1010
809
  const message = formattedLog.slice(65);
1011
810
  matterLogger.logName = logger;
1012
811
  switch (_level) {
1013
812
  case MatterLogLevel.DEBUG:
1014
- matterLogger.log("debug" /* LogLevel.DEBUG */, message);
813
+ matterLogger.log("debug", message);
1015
814
  break;
1016
815
  case MatterLogLevel.INFO:
1017
- matterLogger.log("info" /* LogLevel.INFO */, message);
816
+ matterLogger.log("info", message);
1018
817
  break;
1019
818
  case MatterLogLevel.NOTICE:
1020
- matterLogger.log("notice" /* LogLevel.NOTICE */, message);
819
+ matterLogger.log("notice", message);
1021
820
  break;
1022
821
  case MatterLogLevel.WARN:
1023
- matterLogger.log("warn" /* LogLevel.WARN */, message);
822
+ matterLogger.log("warn", message);
1024
823
  break;
1025
824
  case MatterLogLevel.ERROR:
1026
- matterLogger.log("error" /* LogLevel.ERROR */, message);
825
+ matterLogger.log("error", message);
1027
826
  break;
1028
827
  case MatterLogLevel.FATAL:
1029
- matterLogger.log("fatal" /* LogLevel.FATAL */, message);
828
+ matterLogger.log("fatal", message);
1030
829
  break;
1031
830
  default:
1032
- matterLogger.log("debug" /* LogLevel.DEBUG */, message);
831
+ matterLogger.log("debug", message);
1033
832
  break;
1034
833
  }
1035
834
  };
1036
835
  }
1037
- /**
1038
- * Creates a Matter File Logger.
1039
- *
1040
- * @param {string} filePath - The path to the log file.
1041
- * @param {boolean} [unlink=false] - Whether to unlink the log file before creating a new one.
1042
- * @returns {Function} - A function that logs formatted messages to the log file.
1043
- */
1044
836
  async createMatterFileLogger(filePath, unlink = false) {
1045
- // 2024-08-21 08:55:19.488 DEBUG InteractionMessenger Sending DataReport chunk with 28 attributes and 0 events: 1004 bytes
1046
837
  let fileSize = 0;
1047
838
  if (unlink) {
1048
839
  try {
@@ -1091,21 +882,12 @@ export class Matterbridge extends EventEmitter {
1091
882
  }
1092
883
  };
1093
884
  }
1094
- /**
1095
- * Restarts the process by exiting the current instance and loading a new instance.
1096
- */
1097
885
  async restartProcess() {
1098
886
  await this.cleanup('restarting...', true);
1099
887
  }
1100
- /**
1101
- * Shut down the process by exiting the current process.
1102
- */
1103
888
  async shutdownProcess() {
1104
889
  await this.cleanup('shutting down...', false);
1105
890
  }
1106
- /**
1107
- * Update matterbridge and and shut down the process.
1108
- */
1109
891
  async updateProcess() {
1110
892
  this.log.info('Updating matterbridge...');
1111
893
  try {
@@ -1118,9 +900,6 @@ export class Matterbridge extends EventEmitter {
1118
900
  this.frontend.wssSendRestartRequired();
1119
901
  await this.cleanup('updating...', false);
1120
902
  }
1121
- /**
1122
- * Unregister all devices and shut down the process.
1123
- */
1124
903
  async unregisterAndShutdownProcess() {
1125
904
  this.log.info('Unregistering all devices and shutting down...');
1126
905
  for (const plugin of this.plugins) {
@@ -1128,9 +907,6 @@ export class Matterbridge extends EventEmitter {
1128
907
  }
1129
908
  await this.cleanup('unregistered all devices and shutting down...', false);
1130
909
  }
1131
- /**
1132
- * Reset commissioning and shut down the process.
1133
- */
1134
910
  async shutdownProcessAndReset() {
1135
911
  this.log.info('Resetting Matterbridge commissioning information...');
1136
912
  await this.matterStorageManager?.createContext('events')?.clearAll();
@@ -1142,12 +918,8 @@ export class Matterbridge extends EventEmitter {
1142
918
  this.log.info('Matter storage reset done! Remove the bridge from the controller.');
1143
919
  await this.cleanup('shutting down with reset...', false);
1144
920
  }
1145
- /**
1146
- * Factory reset and shut down the process.
1147
- */
1148
921
  async shutdownProcessAndFactoryReset() {
1149
922
  try {
1150
- // Delete old matter storage file and backup
1151
923
  const file = path.join(this.matterbridgeDirectory, 'matterbridge' + (getParameter('profile') ? '.' + getParameter('profile') : '') + '.json');
1152
924
  this.log.info(`Unlinking old matter storage file: ${file}`);
1153
925
  await fs.unlink(file);
@@ -1161,7 +933,6 @@ export class Matterbridge extends EventEmitter {
1161
933
  }
1162
934
  }
1163
935
  try {
1164
- // Delete matter node storage directory with its subdirectories and backup
1165
936
  const dir = path.join(this.matterbridgeDirectory, 'matterstorage' + (getParameter('profile') ? '.' + getParameter('profile') : ''));
1166
937
  this.log.info(`Removing matter node storage directory: ${dir}`);
1167
938
  await fs.rm(dir, { recursive: true });
@@ -1175,7 +946,6 @@ export class Matterbridge extends EventEmitter {
1175
946
  }
1176
947
  }
1177
948
  try {
1178
- // Delete node storage directory with its subdirectories and backup
1179
949
  const dir = path.join(this.matterbridgeDirectory, 'storage' + (getParameter('profile') ? '.' + getParameter('profile') : ''));
1180
950
  this.log.info(`Removing storage directory: ${dir}`);
1181
951
  await fs.rm(dir, { recursive: true });
@@ -1195,41 +965,30 @@ export class Matterbridge extends EventEmitter {
1195
965
  this.devices.clear();
1196
966
  await this.cleanup('shutting down with factory reset...', false);
1197
967
  }
1198
- /**
1199
- * Cleans up the Matterbridge instance.
1200
- * @param message - The cleanup message.
1201
- * @param restart - Indicates whether to restart the instance after cleanup. Default is `false`.
1202
- * @returns A promise that resolves when the cleanup is completed.
1203
- */
1204
968
  async cleanup(message, restart = false) {
1205
969
  if (this.initialized && !this.hasCleanupStarted) {
1206
970
  this.hasCleanupStarted = true;
1207
971
  this.log.info(message);
1208
- // Clear the start matter interval
1209
972
  if (this.startMatterInterval) {
1210
973
  clearInterval(this.startMatterInterval);
1211
974
  this.startMatterInterval = undefined;
1212
975
  this.log.debug('Start matter interval cleared');
1213
976
  }
1214
- // Clear the check update interval
1215
977
  if (this.checkUpdateInterval) {
1216
978
  clearInterval(this.checkUpdateInterval);
1217
979
  this.checkUpdateInterval = undefined;
1218
980
  this.log.debug('Check update interval cleared');
1219
981
  }
1220
- // Clear the configure timeout
1221
982
  if (this.configureTimeout) {
1222
983
  clearTimeout(this.configureTimeout);
1223
984
  this.configureTimeout = undefined;
1224
985
  this.log.debug('Matterbridge configure timeout cleared');
1225
986
  }
1226
- // Clear the reachability timeout
1227
987
  if (this.reachabilityTimeout) {
1228
988
  clearTimeout(this.reachabilityTimeout);
1229
989
  this.reachabilityTimeout = undefined;
1230
990
  this.log.debug('Matterbridge reachability timeout cleared');
1231
991
  }
1232
- // Calling the shutdown method of each plugin and clear the plugins reachability timeout
1233
992
  for (const plugin of this.plugins) {
1234
993
  if (!plugin.enabled || plugin.error)
1235
994
  continue;
@@ -1240,9 +999,7 @@ export class Matterbridge extends EventEmitter {
1240
999
  this.log.debug(`Plugin ${plg}${plugin.name}${db} reachability timeout cleared`);
1241
1000
  }
1242
1001
  }
1243
- // Stop the frontend
1244
1002
  await this.frontend.stop();
1245
- // Stopping matter server nodes
1246
1003
  this.log.notice(`Stopping matter server nodes in ${this.bridgeMode} mode...`);
1247
1004
  if (this.bridgeMode === 'bridge') {
1248
1005
  if (this.serverNode) {
@@ -1259,35 +1016,16 @@ export class Matterbridge extends EventEmitter {
1259
1016
  }
1260
1017
  }
1261
1018
  this.log.notice('Stopped matter server nodes');
1262
- // Stop matter storage
1263
1019
  await this.stopMatterStorage();
1264
- // Remove the matterfilelogger
1265
1020
  try {
1266
1021
  Logger.removeLogger('matterfilelogger');
1267
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1268
1022
  }
1269
1023
  catch (error) {
1270
- // this.log.debug(`Error removing the matterfilelogger for file ${CYAN}${path.join(this.matterbridgeDirectory, this.matterLoggerFile)}${er}: ${error instanceof Error ? error.message : error}`);
1271
1024
  }
1272
- // Serialize registeredDevices
1273
1025
  if (this.nodeStorage && this.nodeContext) {
1274
- /*
1275
- TODO: Implement serialization of registered devices in edge mode
1276
- this.log.info('Saving registered devices...');
1277
- const serializedRegisteredDevices: SerializedMatterbridgeEndpoint[] = [];
1278
- this.devices.forEach(async (device) => {
1279
- const serializedMatterbridgeDevice = MatterbridgeEndpoint.serialize(device);
1280
- // this.log.info(`- ${serializedMatterbridgeDevice.deviceName}${rs}\n`, serializedMatterbridgeDevice);
1281
- if (serializedMatterbridgeDevice) serializedRegisteredDevices.push(serializedMatterbridgeDevice);
1282
- });
1283
- await this.nodeContext.set<SerializedMatterbridgeEndpoint[]>('devices', serializedRegisteredDevices);
1284
- this.log.info(`Saved registered devices (${serializedRegisteredDevices?.length})`);
1285
- */
1286
- // Clear nodeContext and nodeStorage (they just need 1000ms to write the data to disk)
1287
1026
  this.log.debug(`Closing node storage context for ${plg}Matterbridge${db}...`);
1288
1027
  await this.nodeContext.close();
1289
1028
  this.nodeContext = undefined;
1290
- // Clear nodeContext for each plugin (they just need 1000ms to write the data to disk)
1291
1029
  for (const plugin of this.plugins) {
1292
1030
  if (plugin.nodeContext) {
1293
1031
  this.log.debug(`Closing node storage context for plugin ${plg}${plugin.name}${db}...`);
@@ -1304,13 +1042,12 @@ export class Matterbridge extends EventEmitter {
1304
1042
  }
1305
1043
  this.plugins.clear();
1306
1044
  this.devices.clear();
1307
- // Deregisters the process handlers
1308
1045
  this.deregisterProcesslHandlers();
1309
1046
  if (restart) {
1310
1047
  if (message === 'updating...') {
1311
1048
  this.log.info('Cleanup completed. Updating...');
1312
1049
  Matterbridge.instance = undefined;
1313
- this.emit('update'); // Restart the process but the update has been done before
1050
+ this.emit('update');
1314
1051
  }
1315
1052
  else if (message === 'restarting...') {
1316
1053
  this.log.info('Cleanup completed. Restarting...');
@@ -1327,14 +1064,6 @@ export class Matterbridge extends EventEmitter {
1327
1064
  this.initialized = false;
1328
1065
  }
1329
1066
  }
1330
- /**
1331
- * Creates and configures the server node for an accessory plugin for a given device.
1332
- *
1333
- * @param {RegisteredPlugin} plugin - The plugin to configure.
1334
- * @param {MatterbridgeEndpoint} device - The device to associate with the plugin.
1335
- * @param {boolean} [start=false] - Whether to start the server node after adding the device.
1336
- * @returns {Promise<void>} A promise that resolves when the server node for the accessory plugin is created and configured.
1337
- */
1338
1067
  async createAccessoryPlugin(plugin, device, start = false) {
1339
1068
  if (!plugin.locked && device.deviceName && device.vendorId && device.productId && device.vendorName && device.productName) {
1340
1069
  plugin.locked = true;
@@ -1346,13 +1075,6 @@ export class Matterbridge extends EventEmitter {
1346
1075
  await this.startServerNode(plugin.serverNode);
1347
1076
  }
1348
1077
  }
1349
- /**
1350
- * Creates and configures the server node for a dynamic plugin.
1351
- *
1352
- * @param {RegisteredPlugin} plugin - The plugin to configure.
1353
- * @param {boolean} [start=false] - Whether to start the server node after adding the aggregator node.
1354
- * @returns {Promise<void>} A promise that resolves when the server node for the dynamic plugin is created and configured.
1355
- */
1356
1078
  async createDynamicPlugin(plugin, start = false) {
1357
1079
  if (!plugin.locked) {
1358
1080
  plugin.locked = true;
@@ -1364,13 +1086,7 @@ export class Matterbridge extends EventEmitter {
1364
1086
  await this.startServerNode(plugin.serverNode);
1365
1087
  }
1366
1088
  }
1367
- /**
1368
- * Starts the Matterbridge in bridge mode.
1369
- * @private
1370
- * @returns {Promise<void>} A promise that resolves when the Matterbridge is started.
1371
- */
1372
1089
  async startBridge() {
1373
- // Plugins are configured by a timer when matter server is started and plugin.configured is set to true
1374
1090
  if (!this.matterStorageManager)
1375
1091
  throw new Error('No storage manager initialized');
1376
1092
  if (!this.matterbridgeContext)
@@ -1407,9 +1123,7 @@ export class Matterbridge extends EventEmitter {
1407
1123
  clearInterval(this.startMatterInterval);
1408
1124
  this.startMatterInterval = undefined;
1409
1125
  this.log.debug('Cleared startMatterInterval interval for Matterbridge');
1410
- // Start the Matter server node
1411
1126
  this.startServerNode(this.serverNode);
1412
- // Configure the plugins
1413
1127
  this.configureTimeout = setTimeout(async () => {
1414
1128
  for (const plugin of this.plugins) {
1415
1129
  if (!plugin.enabled || !plugin.loaded || !plugin.started || plugin.error)
@@ -1424,7 +1138,6 @@ export class Matterbridge extends EventEmitter {
1424
1138
  }
1425
1139
  this.frontend.wssSendRefreshRequired();
1426
1140
  }, 30 * 1000);
1427
- // Setting reachability to true
1428
1141
  this.reachabilityTimeout = setTimeout(() => {
1429
1142
  this.log.info(`Setting reachability to true for ${plg}Matterbridge${db}`);
1430
1143
  if (this.serverNode)
@@ -1435,14 +1148,7 @@ export class Matterbridge extends EventEmitter {
1435
1148
  }, 60 * 1000);
1436
1149
  }, 1000);
1437
1150
  }
1438
- /**
1439
- * Starts the Matterbridge in childbridge mode.
1440
- * @private
1441
- * @returns {Promise<void>} A promise that resolves when the Matterbridge is started.
1442
- */
1443
1151
  async startChildbridge() {
1444
- // Matterbridge.addBridgedDevice creates the commissionig servers and add the devices to the the commissioning server or to the aggregator
1445
- // Plugins are configured by a timer when matter server is started and plugin.configured is set to true
1446
1152
  if (!this.matterStorageManager)
1447
1153
  throw new Error('No storage manager initialized');
1448
1154
  for (const plugin of this.plugins) {
@@ -1489,13 +1195,12 @@ export class Matterbridge extends EventEmitter {
1489
1195
  clearInterval(this.startMatterInterval);
1490
1196
  this.startMatterInterval = undefined;
1491
1197
  this.log.debug('Cleared startMatterInterval interval in childbridge mode');
1492
- // Configure the plugins
1493
1198
  this.configureTimeout = setTimeout(async () => {
1494
1199
  for (const plugin of this.plugins) {
1495
1200
  if (!plugin.enabled || !plugin.loaded || !plugin.started || plugin.error)
1496
1201
  continue;
1497
1202
  try {
1498
- await this.plugins.configure(plugin); // TODO No await do it in parallel
1203
+ await this.plugins.configure(plugin);
1499
1204
  }
1500
1205
  catch (error) {
1501
1206
  plugin.error = true;
@@ -1523,9 +1228,7 @@ export class Matterbridge extends EventEmitter {
1523
1228
  this.log.error(`Node storage context not found for plugin ${plg}${plugin.name}${er}`);
1524
1229
  continue;
1525
1230
  }
1526
- // Start the Matter server node
1527
1231
  this.startServerNode(plugin.serverNode);
1528
- // Setting reachability to true
1529
1232
  plugin.reachabilityTimeout = setTimeout(() => {
1530
1233
  this.log.info(`Setting reachability to true for ${plg}${plugin.name}${db}`);
1531
1234
  if (plugin.serverNode)
@@ -1539,219 +1242,9 @@ export class Matterbridge extends EventEmitter {
1539
1242
  }
1540
1243
  }, 1000);
1541
1244
  }
1542
- /**
1543
- * Starts the Matterbridge controller.
1544
- * @private
1545
- * @returns {Promise<void>} A promise that resolves when the Matterbridge is started.
1546
- */
1547
1245
  async startController() {
1548
- /*
1549
- if (!this.storageManager) {
1550
- this.log.error('No storage manager initialized');
1551
- await this.cleanup('No storage manager initialized');
1552
- return;
1553
- }
1554
- this.log.info('Creating context: mattercontrollerContext');
1555
- this.mattercontrollerContext = this.storageManager.createContext('mattercontrollerContext');
1556
- if (!this.mattercontrollerContext) {
1557
- this.log.error('No storage context mattercontrollerContext initialized');
1558
- await this.cleanup('No storage context mattercontrollerContext initialized');
1559
- return;
1560
- }
1561
-
1562
- this.log.debug('Starting matterbridge in mode', this.bridgeMode);
1563
- this.matterServer = await this.createMatterServer(this.storageManager);
1564
- this.log.info('Creating matter commissioning controller');
1565
- this.commissioningController = new CommissioningController({
1566
- autoConnect: false,
1567
- });
1568
- this.log.info('Adding matter commissioning controller to matter server');
1569
- await this.matterServer.addCommissioningController(this.commissioningController);
1570
-
1571
- this.log.info('Starting matter server');
1572
- await this.matterServer.start();
1573
- this.log.info('Matter server started');
1574
-
1575
- if (hasParameter('pairingcode')) {
1576
- this.log.info('Pairing device with pairingcode:', getParameter('pairingcode'));
1577
- const pairingCode = getParameter('pairingcode');
1578
- const ip = this.mattercontrollerContext.has('ip') ? this.mattercontrollerContext.get<string>('ip') : undefined;
1579
- const port = this.mattercontrollerContext.has('port') ? this.mattercontrollerContext.get<number>('port') : undefined;
1580
-
1581
- let longDiscriminator, setupPin, shortDiscriminator;
1582
- if (pairingCode !== undefined) {
1583
- const pairingCodeCodec = ManualPairingCodeCodec.decode(pairingCode);
1584
- shortDiscriminator = pairingCodeCodec.shortDiscriminator;
1585
- longDiscriminator = undefined;
1586
- setupPin = pairingCodeCodec.passcode;
1587
- this.log.info(`Data extracted from pairing code: ${Logger.toJSON(pairingCodeCodec)}`);
1588
- } else {
1589
- longDiscriminator = await this.mattercontrollerContext.get('longDiscriminator', 3840);
1590
- if (longDiscriminator > 4095) throw new Error('Discriminator value must be less than 4096');
1591
- setupPin = this.mattercontrollerContext.get('pin', 20202021);
1592
- }
1593
- if ((shortDiscriminator === undefined && longDiscriminator === undefined) || setupPin === undefined) {
1594
- throw new Error('Please specify the longDiscriminator of the device to commission with -longDiscriminator or provide a valid passcode with -passcode');
1595
- }
1596
-
1597
- const commissioningOptions: ControllerCommissioningFlowOptions = {
1598
- regulatoryLocation: GeneralCommissioning.RegulatoryLocationType.IndoorOutdoor,
1599
- regulatoryCountryCode: 'XX',
1600
- };
1601
- const options = {
1602
- commissioning: commissioningOptions,
1603
- discovery: {
1604
- knownAddress: ip !== undefined && port !== undefined ? { ip, port, type: 'udp' } : undefined,
1605
- identifierData: longDiscriminator !== undefined ? { longDiscriminator } : shortDiscriminator !== undefined ? { shortDiscriminator } : {},
1606
- },
1607
- passcode: setupPin,
1608
- } as NodeCommissioningOptions;
1609
- this.log.info('Commissioning with options:', options);
1610
- const nodeId = await this.commissioningController.commissionNode(options);
1611
- this.log.info(`Commissioning successfully done with nodeId: ${nodeId}`);
1612
- this.log.info('ActiveSessionInformation:', this.commissioningController.getActiveSessionInformation());
1613
- } // (hasParameter('pairingcode'))
1614
-
1615
- if (hasParameter('unpairall')) {
1616
- this.log.info('***Commissioning controller unpairing all nodes...');
1617
- const nodeIds = this.commissioningController.getCommissionedNodes();
1618
- for (const nodeId of nodeIds) {
1619
- this.log.info('***Commissioning controller unpairing node:', nodeId);
1620
- await this.commissioningController.removeNode(nodeId);
1621
- }
1622
- return;
1623
- }
1624
-
1625
- if (hasParameter('discover')) {
1626
- // const discover = await this.commissioningController.discoverCommissionableDevices({ productId: 0x8000, deviceType: 0xfff1 });
1627
- // console.log(discover);
1628
- }
1629
-
1630
- if (!this.commissioningController.isCommissioned()) {
1631
- this.log.info('***Commissioning controller is not commissioned: use matterbridge -controller -pairingcode [pairingcode] to commission a device');
1632
- return;
1633
- }
1634
-
1635
- const nodeIds = this.commissioningController.getCommissionedNodes();
1636
- this.log.info(`***Commissioning controller is commissioned ${this.commissioningController.isCommissioned()} and has ${nodeIds.length} nodes commisioned: `);
1637
- for (const nodeId of nodeIds) {
1638
- this.log.info(`***Connecting to commissioned node: ${nodeId}`);
1639
-
1640
- const node = await this.commissioningController.connectNode(nodeId, {
1641
- autoSubscribe: false,
1642
- attributeChangedCallback: (peerNodeId, { path: { nodeId, clusterId, endpointId, attributeName }, value }) =>
1643
- this.log.info(`***Commissioning controller attributeChangedCallback ${peerNodeId}: attribute ${nodeId}/${endpointId}/${clusterId}/${attributeName} changed to ${Logger.toJSON(value)}`),
1644
- eventTriggeredCallback: (peerNodeId, { path: { nodeId, clusterId, endpointId, eventName }, events }) =>
1645
- this.log.info(`***Commissioning controller eventTriggeredCallback ${peerNodeId}: Event ${nodeId}/${endpointId}/${clusterId}/${eventName} triggered with ${Logger.toJSON(events)}`),
1646
- stateInformationCallback: (peerNodeId, info) => {
1647
- switch (info) {
1648
- case NodeStateInformation.Connected:
1649
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} connected`);
1650
- break;
1651
- case NodeStateInformation.Disconnected:
1652
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} disconnected`);
1653
- break;
1654
- case NodeStateInformation.Reconnecting:
1655
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} reconnecting`);
1656
- break;
1657
- case NodeStateInformation.WaitingForDeviceDiscovery:
1658
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} waiting for device discovery`);
1659
- break;
1660
- case NodeStateInformation.StructureChanged:
1661
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} structure changed`);
1662
- break;
1663
- case NodeStateInformation.Decommissioned:
1664
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} decommissioned`);
1665
- break;
1666
- default:
1667
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} NodeStateInformation.${info}`);
1668
- break;
1669
- }
1670
- },
1671
- });
1672
-
1673
- node.logStructure();
1674
-
1675
- // Get the interaction client
1676
- this.log.info('Getting the interaction client');
1677
- const interactionClient = await node.getInteractionClient();
1678
- let cluster;
1679
- let attributes;
1680
-
1681
- // Log BasicInformationCluster
1682
- cluster = BasicInformationCluster;
1683
- attributes = await interactionClient.getMultipleAttributes({
1684
- attributes: [{ clusterId: cluster.id }],
1685
- });
1686
- if (attributes.length > 0) this.log.info(`Cluster: ${idn}${cluster.name}${rs}${nf} attributes:`);
1687
- attributes.forEach((attribute) => {
1688
- this.log.info(
1689
- `- 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}`,
1690
- );
1691
- });
1692
-
1693
- // Log PowerSourceCluster
1694
- cluster = PowerSourceCluster;
1695
- attributes = await interactionClient.getMultipleAttributes({
1696
- attributes: [{ clusterId: cluster.id }],
1697
- });
1698
- if (attributes.length > 0) this.log.info(`Cluster: ${idn}${cluster.name}${rs}${nf} attributes:`);
1699
- attributes.forEach((attribute) => {
1700
- this.log.info(
1701
- `- 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}`,
1702
- );
1703
- });
1704
-
1705
- // Log ThreadNetworkDiagnostics
1706
- cluster = ThreadNetworkDiagnosticsCluster;
1707
- attributes = await interactionClient.getMultipleAttributes({
1708
- attributes: [{ clusterId: cluster.id }],
1709
- });
1710
- if (attributes.length > 0) this.log.info(`Cluster: ${idn}${cluster.name}${rs}${nf} attributes:`);
1711
- attributes.forEach((attribute) => {
1712
- this.log.info(
1713
- `- 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}`,
1714
- );
1715
- });
1716
-
1717
- // Log SwitchCluster
1718
- cluster = SwitchCluster;
1719
- attributes = await interactionClient.getMultipleAttributes({
1720
- attributes: [{ clusterId: cluster.id }],
1721
- });
1722
- if (attributes.length > 0) this.log.info(`Cluster: ${idn}${cluster.name}${rs}${nf} attributes:`);
1723
- attributes.forEach((attribute) => {
1724
- this.log.info(
1725
- `- 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}`,
1726
- );
1727
- });
1728
-
1729
- this.log.info('Subscribing to all attributes and events');
1730
- await node.subscribeAllAttributesAndEvents({
1731
- ignoreInitialTriggers: false,
1732
- attributeChangedCallback: ({ path: { nodeId, clusterId, endpointId, attributeName }, version, value }) =>
1733
- this.log.info(
1734
- `***${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}`,
1735
- ),
1736
- eventTriggeredCallback: ({ path: { nodeId, clusterId, endpointId, eventName }, events }) => {
1737
- this.log.info(
1738
- `***${db}Commissioning controller eventTriggeredCallback: event ${BLUE}${nodeId}${db}/${or}${endpointId}${db}/${hk}${getClusterNameById(clusterId)}${db}/${zb}${eventName}${db} triggered with ${debugStringify(events ?? { none: true })}`,
1739
- );
1740
- },
1741
- });
1742
- this.log.info('Subscribed to all attributes and events');
1743
- }
1744
- */
1745
1246
  }
1746
- /** ***********************************************************************************************************************************/
1747
- /** Matter.js methods */
1748
- /** ***********************************************************************************************************************************/
1749
- /**
1750
- * Starts the matter storage process with name Matterbridge.
1751
- * @returns {Promise<void>} - A promise that resolves when the storage process is started.
1752
- */
1753
1247
  async startMatterStorage() {
1754
- // Setup Matter storage
1755
1248
  this.log.info(`Starting matter node storage...`);
1756
1249
  this.matterStorageService = this.environment.get(StorageService);
1757
1250
  this.log.info(`Matter node storage service created: ${this.matterStorageService.location}`);
@@ -1759,25 +1252,13 @@ export class Matterbridge extends EventEmitter {
1759
1252
  this.log.info('Matter node storage manager "Matterbridge" created');
1760
1253
  this.matterbridgeContext = await this.createServerNodeContext('Matterbridge', 'Matterbridge', bridge.code, this.aggregatorVendorId, 'Matterbridge', this.aggregatorProductId, 'Matterbridge aggregator');
1761
1254
  this.log.info('Matter node storage started');
1762
- // Backup matter storage since it is created/opened correctly
1763
1255
  await this.backupMatterStorage(path.join(this.matterbridgeDirectory, this.matterStorageName), path.join(this.matterbridgeDirectory, this.matterStorageName + '.backup'));
1764
1256
  }
1765
- /**
1766
- * Makes a backup copy of the specified matter storage directory.
1767
- *
1768
- * @param storageName - The name of the storage directory to be backed up.
1769
- * @param backupName - The name of the backup directory to be created.
1770
- * @returns {Promise<void>} A promise that resolves when the has been done.
1771
- */
1772
1257
  async backupMatterStorage(storageName, backupName) {
1773
1258
  this.log.info('Creating matter node storage backup...');
1774
1259
  await copyDirectory(storageName, backupName);
1775
1260
  this.log.info('Created matter node storage backup');
1776
1261
  }
1777
- /**
1778
- * Stops the matter storage.
1779
- * @returns {Promise<void>} A promise that resolves when the storage is stopped.
1780
- */
1781
1262
  async stopMatterStorage() {
1782
1263
  this.log.info('Closing matter node storage...');
1783
1264
  this.matterStorageManager?.close();
@@ -1786,19 +1267,6 @@ export class Matterbridge extends EventEmitter {
1786
1267
  this.matterbridgeContext = undefined;
1787
1268
  this.log.info('Matter node storage closed');
1788
1269
  }
1789
- /**
1790
- * Creates a server node storage context.
1791
- *
1792
- * @param {string} pluginName - The name of the plugin.
1793
- * @param {string} deviceName - The name of the device.
1794
- * @param {DeviceTypeId} deviceType - The device type of the device.
1795
- * @param {number} vendorId - The vendor ID.
1796
- * @param {string} vendorName - The vendor name.
1797
- * @param {number} productId - The product ID.
1798
- * @param {string} productName - The product name.
1799
- * @param {string} [serialNumber] - The serial number of the device (optional).
1800
- * @returns {Promise<StorageContext>} The storage context for the commissioning server.
1801
- */
1802
1270
  async createServerNodeContext(pluginName, deviceName, deviceType, vendorId, vendorName, productId, productName, serialNumber) {
1803
1271
  if (!this.matterStorageService)
1804
1272
  throw new Error('No storage service initialized');
@@ -1831,15 +1299,6 @@ export class Matterbridge extends EventEmitter {
1831
1299
  this.log.debug(`- hardwareVersion: ${await storageContext.get('hardwareVersion')} hardwareVersionString: ${await storageContext.get('hardwareVersionString')}`);
1832
1300
  return storageContext;
1833
1301
  }
1834
- /**
1835
- * Creates a server node.
1836
- *
1837
- * @param {StorageContext} storageContext - The storage context for the server node.
1838
- * @param {number} [port=5540] - The port number for the server node. Defaults to 5540.
1839
- * @param {number} [passcode=20242025] - The passcode for the server node. Defaults to 20242025.
1840
- * @param {number} [discriminator=3850] - The discriminator for the server node. Defaults to 3850.
1841
- * @returns {Promise<ServerNode<ServerNode.RootEndpoint>>} A promise that resolves to the created server node.
1842
- */
1843
1302
  async createServerNode(storageContext, port = 5540, passcode = 20242025, discriminator = 3850) {
1844
1303
  const storeId = await storageContext.get('storeId');
1845
1304
  this.log.notice(`Creating server node for ${storeId} on port ${port} with passcode ${passcode} and discriminator ${discriminator}...`);
@@ -1849,33 +1308,21 @@ export class Matterbridge extends EventEmitter {
1849
1308
  this.log.debug(`- uniqueId: ${await storageContext.get('uniqueId')}`);
1850
1309
  this.log.debug(`- softwareVersion: ${await storageContext.get('softwareVersion')} softwareVersionString: ${await storageContext.get('softwareVersionString')}`);
1851
1310
  this.log.debug(`- hardwareVersion: ${await storageContext.get('hardwareVersion')} hardwareVersionString: ${await storageContext.get('hardwareVersionString')}`);
1852
- /**
1853
- * Create a Matter ServerNode, which contains the Root Endpoint and all relevant data and configuration
1854
- */
1855
1311
  const serverNode = await ServerNode.create({
1856
- // Required: Give the Node a unique ID which is used to store the state of this node
1857
1312
  id: storeId,
1858
- // Provide Network relevant configuration like the port
1859
- // Optional when operating only one device on a host, Default port is 5540
1860
1313
  network: {
1861
1314
  listeningAddressIpv4: this.ipv4address,
1862
1315
  listeningAddressIpv6: this.ipv6address,
1863
1316
  port,
1864
1317
  },
1865
- // Provide Commissioning relevant settings
1866
- // Optional for development/testing purposes
1867
1318
  commissioning: {
1868
1319
  passcode,
1869
1320
  discriminator,
1870
1321
  },
1871
- // Provide Node announcement settings
1872
- // Optional: If Ommitted some development defaults are used
1873
1322
  productDescription: {
1874
1323
  name: await storageContext.get('deviceName'),
1875
1324
  deviceType: DeviceTypeId(await storageContext.get('deviceType')),
1876
1325
  },
1877
- // Provide defaults for the BasicInformation cluster on the Root endpoint
1878
- // Optional: If Omitted some development defaults are used
1879
1326
  basicInformation: {
1880
1327
  vendorId: VendorId(await storageContext.get('vendorId')),
1881
1328
  vendorName: await storageContext.get('vendorName'),
@@ -1892,13 +1339,12 @@ export class Matterbridge extends EventEmitter {
1892
1339
  },
1893
1340
  });
1894
1341
  const sanitizeFabrics = (fabrics, resetSessions = false) => {
1895
- // New type of fabric information: Record<FabricIndex, ExposedFabricInformation>
1896
1342
  const sanitizedFabrics = this.sanitizeFabricInformations(Array.from(Object.values(fabrics)));
1897
1343
  this.log.info(`Fabrics: ${debugStringify(sanitizedFabrics)}`);
1898
1344
  if (this.bridgeMode === 'bridge') {
1899
1345
  this.matterbridgeFabricInformations = sanitizedFabrics;
1900
1346
  if (resetSessions)
1901
- this.matterbridgeSessionInformations = undefined; // Changed cause Invoke Matterbridge.operationalCredentials.updateFabricLabel is sent after the session is created
1347
+ this.matterbridgeSessionInformations = undefined;
1902
1348
  this.matterbridgePaired = true;
1903
1349
  }
1904
1350
  if (this.bridgeMode === 'childbridge') {
@@ -1906,19 +1352,13 @@ export class Matterbridge extends EventEmitter {
1906
1352
  if (plugin) {
1907
1353
  plugin.fabricInformations = sanitizedFabrics;
1908
1354
  if (resetSessions)
1909
- plugin.sessionInformations = undefined; // Changed cause Invoke Matterbridge.operationalCredentials.updateFabricLabel is sent after the session is created
1355
+ plugin.sessionInformations = undefined;
1910
1356
  plugin.paired = true;
1911
1357
  }
1912
1358
  }
1913
1359
  };
1914
- /**
1915
- * This event is triggered when the device is initially commissioned successfully.
1916
- * This means: It is added to the first fabric.
1917
- */
1918
1360
  serverNode.lifecycle.commissioned.on(() => this.log.notice(`Server node for ${storeId} was initially commissioned successfully!`));
1919
- /** This event is triggered when all fabrics are removed from the device, usually it also does a factory reset then. */
1920
1361
  serverNode.lifecycle.decommissioned.on(() => this.log.notice(`Server node for ${storeId} was fully decommissioned successfully!`));
1921
- /** This event is triggered when the device went online. This means that it is discoverable in the network. */
1922
1362
  serverNode.lifecycle.online.on(async () => {
1923
1363
  this.log.notice(`Server node for ${storeId} is online`);
1924
1364
  if (!serverNode.lifecycle.isCommissioned) {
@@ -1964,7 +1404,6 @@ export class Matterbridge extends EventEmitter {
1964
1404
  }
1965
1405
  this.frontend.wssSendRefreshRequired();
1966
1406
  });
1967
- /** This event is triggered when the device went offline. it is not longer discoverable or connectable in the network. */
1968
1407
  serverNode.lifecycle.offline.on(() => {
1969
1408
  this.log.notice(`Server node for ${storeId} is offline`);
1970
1409
  if (this.bridgeMode === 'bridge') {
@@ -1986,10 +1425,6 @@ export class Matterbridge extends EventEmitter {
1986
1425
  }
1987
1426
  this.frontend.wssSendRefreshRequired();
1988
1427
  });
1989
- /**
1990
- * This event is triggered when a fabric is added, removed or updated on the device. Use this if more granular
1991
- * information is needed.
1992
- */
1993
1428
  serverNode.events.commissioning.fabricsChanged.on((fabricIndex, fabricAction) => {
1994
1429
  let action = '';
1995
1430
  switch (fabricAction) {
@@ -2023,24 +1458,16 @@ export class Matterbridge extends EventEmitter {
2023
1458
  }
2024
1459
  }
2025
1460
  };
2026
- /**
2027
- * This event is triggered when an operative new session was opened by a Controller.
2028
- * It is not triggered for the initial commissioning process, just afterwards for real connections.
2029
- */
2030
1461
  serverNode.events.sessions.opened.on((session) => {
2031
1462
  this.log.notice(`Session opened on server node for ${storeId}: ${debugStringify(session)}`);
2032
1463
  sanitizeSessions(Object.values(serverNode.state.sessions.sessions));
2033
1464
  this.frontend.wssSendRefreshRequired();
2034
1465
  });
2035
- /**
2036
- * This event is triggered when an operative session is closed by a Controller or because the Device goes offline.
2037
- */
2038
1466
  serverNode.events.sessions.closed.on((session) => {
2039
1467
  this.log.notice(`Session closed on server node for ${storeId}: ${debugStringify(session)}`);
2040
1468
  sanitizeSessions(Object.values(serverNode.state.sessions.sessions));
2041
1469
  this.frontend.wssSendRefreshRequired();
2042
1470
  });
2043
- /** This event is triggered when a subscription gets added or removed on an operative session. */
2044
1471
  serverNode.events.sessions.subscriptionsChanged.on((session) => {
2045
1472
  this.log.notice(`Session subscriptions changed on server node for ${storeId}: ${debugStringify(session)}`);
2046
1473
  sanitizeSessions(Object.values(serverNode.state.sessions.sessions));
@@ -2049,39 +1476,38 @@ export class Matterbridge extends EventEmitter {
2049
1476
  this.log.info(`Created server node for ${storeId}`);
2050
1477
  return serverNode;
2051
1478
  }
2052
- /**
2053
- * Starts the specified server node.
2054
- *
2055
- * @param {ServerNode} [matterServerNode] - The server node to start.
2056
- * @returns {Promise<void>} A promise that resolves when the server node has started.
2057
- */
2058
1479
  async startServerNode(matterServerNode) {
2059
1480
  if (!matterServerNode)
2060
1481
  return;
2061
1482
  this.log.notice(`Starting ${matterServerNode.id} server node`);
2062
1483
  await matterServerNode.start();
2063
1484
  }
2064
- /**
2065
- * Stops the specified server node.
2066
- *
2067
- * @param {ServerNode} matterServerNode - The server node to stop.
2068
- * @returns {Promise<void>} A promise that resolves when the server node has stopped.
2069
- */
2070
1485
  async stopServerNode(matterServerNode) {
2071
1486
  if (!matterServerNode)
2072
1487
  return;
2073
1488
  this.log.notice(`Closing ${matterServerNode.id} server node`);
2074
- await matterServerNode.close();
2075
- this.log.info(`Closed ${matterServerNode.id} server node`);
2076
- // await matterServerNode.env.get(MdnsService)[Symbol.asyncDispose]();
2077
- // this.log.info(`Closed ${matterServerNode.id} MdnsService`);
1489
+ const withTimeout = (promise, ms) => {
1490
+ return new Promise((resolve, reject) => {
1491
+ const timer = setTimeout(() => reject(new Error('Operation timed out')), ms);
1492
+ promise
1493
+ .then((result) => {
1494
+ clearTimeout(timer);
1495
+ resolve(result);
1496
+ })
1497
+ .catch((error) => {
1498
+ clearTimeout(timer);
1499
+ reject(error);
1500
+ });
1501
+ });
1502
+ };
1503
+ try {
1504
+ await withTimeout(matterServerNode.close(), 5000);
1505
+ this.log.info(`Closed ${matterServerNode.id} server node`);
1506
+ }
1507
+ catch (error) {
1508
+ this.log.error(`Failed to close ${matterServerNode.id} server node: ${error instanceof Error ? error.message : error}`);
1509
+ }
2078
1510
  }
2079
- /**
2080
- * Advertises the specified server node if it is commissioned.
2081
- *
2082
- * @param {ServerNode} [matterServerNode] - The server node to advertise.
2083
- * @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.
2084
- */
2085
1511
  async advertiseServerNode(matterServerNode) {
2086
1512
  if (matterServerNode && matterServerNode.lifecycle.isCommissioned) {
2087
1513
  await matterServerNode.env.get(DeviceCommissioner)?.allowBasicCommissioning();
@@ -2091,32 +1517,17 @@ export class Matterbridge extends EventEmitter {
2091
1517
  }
2092
1518
  return undefined;
2093
1519
  }
2094
- /**
2095
- * Creates an aggregator node with the specified storage context.
2096
- *
2097
- * @param {StorageContext} storageContext - The storage context for the aggregator node.
2098
- * @returns {Promise<EndpointNode<AggregatorEndpoint>>} A promise that resolves to the created aggregator node.
2099
- */
2100
1520
  async createAggregatorNode(storageContext) {
2101
1521
  this.log.notice(`Creating ${await storageContext.get('storeId')} aggregator `);
2102
1522
  const aggregatorNode = new EndpointNode(AggregatorEndpoint, { id: `${await storageContext.get('storeId')}` });
2103
1523
  return aggregatorNode;
2104
1524
  }
2105
- /**
2106
- * Adds a MatterbridgeEndpoint to the specified plugin.
2107
- *
2108
- * @param {string} pluginName - The name of the plugin.
2109
- * @param {MatterbridgeEndpoint} device - The device to add as a bridged endpoint.
2110
- * @returns {Promise<void>} A promise that resolves when the bridged endpoint has been added.
2111
- */
2112
1525
  async addBridgedEndpoint(pluginName, device) {
2113
- // Check if the plugin is registered
2114
1526
  const plugin = this.plugins.get(pluginName);
2115
1527
  if (!plugin) {
2116
1528
  this.log.error(`Error adding bridged endpoint ${dev}${device.deviceName}${er} (${zb}${device.id}${er}) plugin ${plg}${pluginName}${er} not found`);
2117
1529
  return;
2118
1530
  }
2119
- // Register and add the device to the matterbridge aggregator node
2120
1531
  if (this.bridgeMode === 'bridge') {
2121
1532
  this.log.debug(`Adding bridged endpoint ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} to Matterbridge aggregator node`);
2122
1533
  if (!this.aggregatorNode)
@@ -2139,26 +1550,16 @@ export class Matterbridge extends EventEmitter {
2139
1550
  plugin.registeredDevices++;
2140
1551
  if (plugin.addedDevices !== undefined)
2141
1552
  plugin.addedDevices++;
2142
- // Add the device to the DeviceManager
2143
1553
  this.devices.set(device);
2144
1554
  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}`);
2145
1555
  }
2146
- /**
2147
- * Removes a MatterbridgeEndpoint from the specified plugin.
2148
- *
2149
- * @param {string} pluginName - The name of the plugin.
2150
- * @param {MatterbridgeEndpoint} device - The device to remove as a bridged endpoint.
2151
- * @returns {Promise<void>} A promise that resolves when the bridged endpoint has been removed.
2152
- */
2153
1556
  async removeBridgedEndpoint(pluginName, device) {
2154
1557
  this.log.debug(`Removing bridged endpoint ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} (${zb}${device.name}${db}) for plugin ${plg}${pluginName}${db}`);
2155
- // Check if the plugin is registered
2156
1558
  const plugin = this.plugins.get(pluginName);
2157
1559
  if (!plugin) {
2158
1560
  this.log.error(`Error removing bridged endpoint ${dev}${device.deviceName}${er} (${zb}${device.name}${er}) for plugin ${plg}${pluginName}${er}: plugin not found`);
2159
1561
  return;
2160
1562
  }
2161
- // Register and add the device to the matterbridge aggregator node
2162
1563
  if (this.bridgeMode === 'bridge') {
2163
1564
  if (!this.aggregatorNode) {
2164
1565
  this.log.error(`Error removing bridged endpoint ${dev}${device.deviceName}${er} (${zb}${device.name}${er}) for plugin ${plg}${pluginName}${er}: aggregator node not found`);
@@ -2173,7 +1574,6 @@ export class Matterbridge extends EventEmitter {
2173
1574
  }
2174
1575
  else if (this.bridgeMode === 'childbridge') {
2175
1576
  if (plugin.type === 'AccessoryPlatform') {
2176
- // Nothing to do here since the server node has no aggregator node but only the device itself
2177
1577
  }
2178
1578
  else if (plugin.type === 'DynamicPlatform') {
2179
1579
  if (!plugin.aggregatorNode) {
@@ -2187,7 +1587,6 @@ export class Matterbridge extends EventEmitter {
2187
1587
  plugin.registeredDevices--;
2188
1588
  if (plugin.addedDevices !== undefined)
2189
1589
  plugin.addedDevices--;
2190
- // Close the server node TODO check if this is correct
2191
1590
  if (plugin.registeredDevices === 0 && plugin.addedDevices === 0) {
2192
1591
  if (plugin.serverNode) {
2193
1592
  await this.stopServerNode(plugin.serverNode);
@@ -2198,27 +1597,14 @@ export class Matterbridge extends EventEmitter {
2198
1597
  }
2199
1598
  }
2200
1599
  }
2201
- // Remove the device from the DeviceManager
2202
1600
  this.devices.remove(device);
2203
1601
  }
2204
- /**
2205
- * Removes all bridged endpoints from the specified plugin.
2206
- *
2207
- * @param {string} pluginName - The name of the plugin.
2208
- * @returns {Promise<void>} A promise that resolves when all bridged endpoints have been removed.
2209
- */
2210
1602
  async removeAllBridgedEndpoints(pluginName) {
2211
1603
  this.log.debug(`Removing all bridged endpoints for plugin ${plg}${pluginName}${db}`);
2212
1604
  for (const device of this.devices.array().filter((device) => device.plugin === pluginName)) {
2213
1605
  await this.removeBridgedEndpoint(pluginName, device);
2214
1606
  }
2215
1607
  }
2216
- /**
2217
- * Sanitizes the fabric information by converting bigint properties to strings because `res.json` doesn't support bigint.
2218
- *
2219
- * @param {ExposedFabricInformation[]} fabricInfo - The array of exposed fabric information objects.
2220
- * @returns {SanitizedExposedFabricInformation[]} An array of sanitized exposed fabric information objects.
2221
- */
2222
1608
  sanitizeFabricInformations(fabricInfo) {
2223
1609
  return fabricInfo.map((info) => {
2224
1610
  return {
@@ -2232,12 +1618,6 @@ export class Matterbridge extends EventEmitter {
2232
1618
  };
2233
1619
  });
2234
1620
  }
2235
- /**
2236
- * Sanitizes the session information by converting bigint properties to strings because `res.json` doesn't support bigint.
2237
- *
2238
- * @param {SessionInformation[]} sessionInfo - The array of session information objects.
2239
- * @returns {SanitizedSessionInformation[]} An array of sanitized session information objects.
2240
- */
2241
1621
  sanitizeSessionInformation(sessionInfo) {
2242
1622
  return sessionInfo
2243
1623
  .filter((session) => session.isPeerActive)
@@ -2265,51 +1645,11 @@ export class Matterbridge extends EventEmitter {
2265
1645
  };
2266
1646
  });
2267
1647
  }
2268
- /**
2269
- * Sets the reachability of a matter server node and trigger ReachableChanged event.
2270
- *
2271
- * @param {ServerNode<ServerNode.RootEndpoint>} serverNode - The commissioning server to set the reachability for.
2272
- * @param {boolean} reachable - The new reachability status.
2273
- */
2274
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
2275
1648
  setServerNodeReachability(serverNode, reachable) {
2276
- /*
2277
- const basicInformationCluster = commissioningServer?.getRootClusterServer(BasicInformationCluster);
2278
- if (basicInformationCluster && basicInformationCluster.attributes.reachable !== undefined) basicInformationCluster.setReachableAttribute(reachable);
2279
- if (basicInformationCluster && basicInformationCluster.triggerReachableChangedEvent) basicInformationCluster.triggerReachableChangedEvent({ reachableNewValue: reachable });
2280
- */
2281
1649
  }
2282
- /**
2283
- * Sets the reachability of the specified matter aggregator and its bridged devices and trigger.
2284
- * @param {EndpointNode<AggregatorEndpoint>} aggregatorNode - The matter aggregator to set the reachability for.
2285
- * @param {boolean} reachable - A boolean indicating the reachability status to set.
2286
- */
2287
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
2288
1650
  setAggregatorReachability(aggregatorNode, reachable) {
2289
- /*
2290
- const basicInformationCluster = matterAggregator.getClusterServer(BasicInformationCluster);
2291
- if (basicInformationCluster && basicInformationCluster.attributes.reachable !== undefined) basicInformationCluster.setReachableAttribute(reachable);
2292
- if (basicInformationCluster && basicInformationCluster.triggerReachableChangedEvent) basicInformationCluster.triggerReachableChangedEvent({ reachableNewValue: reachable });
2293
- matterAggregator.getBridgedDevices().forEach((device) => {
2294
- this.log.debug(`Setting reachability to true for bridged device: ${dev}${device.name}${nf}`);
2295
- device.getClusterServer(BridgedDeviceBasicInformationCluster)?.setReachableAttribute(reachable);
2296
- device.getClusterServer(BridgedDeviceBasicInformationCluster)?.triggerReachableChangedEvent({ reachableNewValue: reachable });
2297
- });
2298
- */
2299
1651
  }
2300
- /**
2301
- * Sets the reachability of a device and trigger.
2302
- *
2303
- * @param {MatterbridgeEndpoint} device - The device to set the reachability for.
2304
- * @param {boolean} reachable - The new reachability status of the device.
2305
- */
2306
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
2307
1652
  setDeviceReachability(device, reachable) {
2308
- /*
2309
- const basicInformationCluster = device.getClusterServer(BasicInformationCluster);
2310
- if (basicInformationCluster && basicInformationCluster.attributes.reachable !== undefined) basicInformationCluster.setReachableAttribute(reachable);
2311
- if (basicInformationCluster && basicInformationCluster.triggerReachableChangedEvent) basicInformationCluster.triggerReachableChangedEvent({ reachableNewValue: reachable });
2312
- */
2313
1653
  }
2314
1654
  getVendorIdName = (vendorId) => {
2315
1655
  if (!vendorId)
@@ -2352,36 +1692,13 @@ export class Matterbridge extends EventEmitter {
2352
1692
  }
2353
1693
  return vendorName;
2354
1694
  };
2355
- /**
2356
- * Spawns a child process with the given command and arguments.
2357
- * @param {string} command - The command to execute.
2358
- * @param {string[]} args - The arguments to pass to the command (default: []).
2359
- * @returns {Promise<boolean>} A promise that resolves when the child process exits successfully, or rejects if there is an error.
2360
- */
2361
1695
  async spawnCommand(command, args = []) {
2362
- /*
2363
- npm > npm.cmd on windows
2364
- cmd.exe ['dir'] on windows
2365
- await this.spawnCommand('npm', ['install', '-g', 'matterbridge']);
2366
- process.on('unhandledRejection', (reason, promise) => {
2367
- this.log.error('Unhandled Rejection at:', promise, 'reason:', reason);
2368
- });
2369
-
2370
- spawn - [14:27:21.125] [Matterbridge:spawn]: changed 38 packages in 4s
2371
- spawn - [14:27:21.125] [Matterbridge:spawn]: 10 packages are looking for funding run `npm fund` for details
2372
- debug - [14:27:21.131] [Matterbridge]: Child process exited with code 0 and signal null
2373
- debug - [14:27:21.131] [Matterbridge]: Child process stdio streams have closed with code 0
2374
- */
2375
1696
  const cmdLine = command + ' ' + args.join(' ');
2376
1697
  if (process.platform === 'win32' && command === 'npm') {
2377
- // Must be spawn('cmd.exe', ['/c', 'npm -g install <package>']);
2378
1698
  const argstring = 'npm ' + args.join(' ');
2379
1699
  args.splice(0, args.length, '/c', argstring);
2380
1700
  command = 'cmd.exe';
2381
1701
  }
2382
- // Decide when using sudo on linux
2383
- // When you need sudo: Spawn stderr: npm error Error: EACCES: permission denied
2384
- // When you don't need sudo: Failed to start child process "npm install -g matterbridge-eve-door": spawn sudo ENOENT
2385
1702
  if (hasParameter('sudo') || (process.platform === 'linux' && command === 'npm' && !hasParameter('docker') && !hasParameter('nosudo'))) {
2386
1703
  args.unshift(command);
2387
1704
  command = 'sudo';
@@ -2440,4 +1757,3 @@ export class Matterbridge extends EventEmitter {
2440
1757
  });
2441
1758
  }
2442
1759
  }
2443
- //# sourceMappingURL=matterbridge.js.map