matterbridge 2.1.3 → 2.1.4-dev.2

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