matterbridge 2.2.0-dev.5 → 2.2.0-dev.7

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 (127) hide show
  1. package/CHANGELOG.md +1 -8
  2. package/dist/cli.js +2 -37
  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 +42 -265
  7. package/dist/index.js +2 -29
  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 +1 -3
  15. package/dist/matterbridge.js +51 -720
  16. package/dist/matterbridgeAccessoryPlatform.js +0 -33
  17. package/dist/matterbridgeBehaviors.js +1 -32
  18. package/dist/matterbridgeDeviceTypes.js +11 -112
  19. package/dist/matterbridgeDynamicPlatform.js +0 -33
  20. package/dist/matterbridgeEndpoint.js +6 -690
  21. package/dist/matterbridgeEndpointHelpers.js +9 -118
  22. package/dist/matterbridgePlatform.js +7 -140
  23. package/dist/matterbridgeTypes.js +0 -24
  24. package/dist/pluginManager.js +3 -229
  25. package/dist/shelly.js +33 -136
  26. package/dist/storage/export.js +0 -1
  27. package/dist/update.js +0 -45
  28. package/dist/utils/colorUtils.js +2 -205
  29. package/dist/utils/copyDirectory.js +1 -37
  30. package/dist/utils/createZip.js +2 -42
  31. package/dist/utils/deepCopy.js +0 -40
  32. package/dist/utils/deepEqual.js +1 -65
  33. package/dist/utils/export.js +0 -1
  34. package/dist/utils/isvalid.js +0 -86
  35. package/dist/utils/network.js +5 -77
  36. package/dist/utils/parameter.js +0 -41
  37. package/dist/utils/wait.js +5 -48
  38. package/frontend/build/asset-manifest.json +3 -3
  39. package/frontend/build/index.html +1 -1
  40. package/frontend/build/static/js/{main.f60aae10.js → main.8240902c.js} +3 -3
  41. package/frontend/build/static/js/main.8240902c.js.map +1 -0
  42. package/npm-shrinkwrap.json +44 -44
  43. package/package.json +2 -2
  44. package/dist/cli.d.ts +0 -28
  45. package/dist/cli.d.ts.map +0 -1
  46. package/dist/cli.js.map +0 -1
  47. package/dist/cluster/export.d.ts.map +0 -1
  48. package/dist/cluster/export.js.map +0 -1
  49. package/dist/defaultConfigSchema.d.ts.map +0 -1
  50. package/dist/defaultConfigSchema.js.map +0 -1
  51. package/dist/deviceManager.d.ts +0 -109
  52. package/dist/deviceManager.d.ts.map +0 -1
  53. package/dist/deviceManager.js.map +0 -1
  54. package/dist/frontend.d.ts +0 -172
  55. package/dist/frontend.d.ts.map +0 -1
  56. package/dist/frontend.js.map +0 -1
  57. package/dist/index.d.ts.map +0 -1
  58. package/dist/index.js.map +0 -1
  59. package/dist/logger/export.d.ts.map +0 -1
  60. package/dist/logger/export.js.map +0 -1
  61. package/dist/matter/behaviors.d.ts.map +0 -1
  62. package/dist/matter/behaviors.js.map +0 -1
  63. package/dist/matter/clusters.d.ts.map +0 -1
  64. package/dist/matter/clusters.js.map +0 -1
  65. package/dist/matter/devices.d.ts.map +0 -1
  66. package/dist/matter/devices.js.map +0 -1
  67. package/dist/matter/endpoints.d.ts.map +0 -1
  68. package/dist/matter/endpoints.js.map +0 -1
  69. package/dist/matter/export.d.ts.map +0 -1
  70. package/dist/matter/export.js.map +0 -1
  71. package/dist/matter/types.d.ts.map +0 -1
  72. package/dist/matter/types.js.map +0 -1
  73. package/dist/matterbridge.d.ts +0 -410
  74. package/dist/matterbridge.d.ts.map +0 -1
  75. package/dist/matterbridge.js.map +0 -1
  76. package/dist/matterbridgeAccessoryPlatform.d.ts.map +0 -1
  77. package/dist/matterbridgeAccessoryPlatform.js.map +0 -1
  78. package/dist/matterbridgeBehaviors.d.ts +0 -148
  79. package/dist/matterbridgeBehaviors.d.ts.map +0 -1
  80. package/dist/matterbridgeBehaviors.js.map +0 -1
  81. package/dist/matterbridgeDeviceTypes.d.ts.map +0 -1
  82. package/dist/matterbridgeDeviceTypes.js.map +0 -1
  83. package/dist/matterbridgeDynamicPlatform.d.ts.map +0 -1
  84. package/dist/matterbridgeDynamicPlatform.js.map +0 -1
  85. package/dist/matterbridgeEndpoint.d.ts +0 -827
  86. package/dist/matterbridgeEndpoint.d.ts.map +0 -1
  87. package/dist/matterbridgeEndpoint.js.map +0 -1
  88. package/dist/matterbridgeEndpointHelpers.d.ts +0 -123
  89. package/dist/matterbridgeEndpointHelpers.d.ts.map +0 -1
  90. package/dist/matterbridgeEndpointHelpers.js.map +0 -1
  91. package/dist/matterbridgePlatform.d.ts +0 -159
  92. package/dist/matterbridgePlatform.d.ts.map +0 -1
  93. package/dist/matterbridgePlatform.js.map +0 -1
  94. package/dist/matterbridgeTypes.d.ts.map +0 -1
  95. package/dist/matterbridgeTypes.js.map +0 -1
  96. package/dist/pluginManager.d.ts +0 -236
  97. package/dist/pluginManager.d.ts.map +0 -1
  98. package/dist/pluginManager.js.map +0 -1
  99. package/dist/shelly.d.ts.map +0 -1
  100. package/dist/shelly.js.map +0 -1
  101. package/dist/storage/export.d.ts.map +0 -1
  102. package/dist/storage/export.js.map +0 -1
  103. package/dist/update.d.ts.map +0 -1
  104. package/dist/update.js.map +0 -1
  105. package/dist/utils/colorUtils.d.ts.map +0 -1
  106. package/dist/utils/colorUtils.js.map +0 -1
  107. package/dist/utils/copyDirectory.d.ts.map +0 -1
  108. package/dist/utils/copyDirectory.js.map +0 -1
  109. package/dist/utils/createZip.d.ts.map +0 -1
  110. package/dist/utils/createZip.js.map +0 -1
  111. package/dist/utils/deepCopy.d.ts.map +0 -1
  112. package/dist/utils/deepCopy.js.map +0 -1
  113. package/dist/utils/deepEqual.d.ts.map +0 -1
  114. package/dist/utils/deepEqual.js.map +0 -1
  115. package/dist/utils/export.d.ts.map +0 -1
  116. package/dist/utils/export.js.map +0 -1
  117. package/dist/utils/isvalid.d.ts.map +0 -1
  118. package/dist/utils/isvalid.js.map +0 -1
  119. package/dist/utils/network.d.ts.map +0 -1
  120. package/dist/utils/network.js.map +0 -1
  121. package/dist/utils/parameter.d.ts.map +0 -1
  122. package/dist/utils/parameter.js.map +0 -1
  123. package/dist/utils/wait.d.ts +0 -43
  124. package/dist/utils/wait.d.ts.map +0 -1
  125. package/dist/utils/wait.js.map +0 -1
  126. package/frontend/build/static/js/main.f60aae10.js.map +0 -1
  127. /package/frontend/build/static/js/{main.f60aae10.js.LICENSE.txt → main.8240902c.js.LICENSE.txt} +0 -0
@@ -1,35 +1,9 @@
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 os from 'node:os';
25
2
  import path from 'node:path';
26
3
  import { promises as fs } from 'node:fs';
27
4
  import EventEmitter from 'node:events';
28
- // AnsiLogger module
29
5
  import { AnsiLogger, UNDERLINE, UNDERLINEOFF, YELLOW, db, debugStringify, BRIGHT, RESET, er, nf, rs, wr, RED, GREEN, zb, CYAN } from './logger/export.js';
30
- // NodeStorage module
31
6
  import { NodeStorageManager } from './storage/export.js';
32
- // Matterbridge
33
7
  import { getParameter, getIntParameter, hasParameter, copyDirectory, withTimeout } from './utils/export.js';
34
8
  import { logInterfaces, getGlobalNodeModules } from './utils/network.js';
35
9
  import { PluginManager } from './pluginManager.js';
@@ -37,18 +11,13 @@ import { DeviceManager } from './deviceManager.js';
37
11
  import { MatterbridgeEndpoint } from './matterbridgeEndpoint.js';
38
12
  import { bridge } from './matterbridgeDeviceTypes.js';
39
13
  import { Frontend } from './frontend.js';
40
- // @matter
41
14
  import { DeviceTypeId, Endpoint as EndpointNode, Logger, LogLevel as MatterLogLevel, LogFormat as MatterLogFormat, VendorId, StorageService, Environment, ServerNode } from '@matter/main';
42
15
  import { DeviceCommissioner, FabricAction, MdnsService, PaseClient } from '@matter/main/protocol';
43
16
  import { AggregatorEndpoint } from '@matter/main/endpoints';
44
17
  import { BridgedDeviceBasicInformationServer } from '@matter/main/behaviors/bridged-device-basic-information';
45
- // Default colors
46
18
  const plg = '\u001B[38;5;33m';
47
19
  const dev = '\u001B[38;5;79m';
48
20
  const typ = '\u001B[38;5;207m';
49
- /**
50
- * Represents the Matterbridge application.
51
- */
52
21
  export class Matterbridge extends EventEmitter {
53
22
  systemInformation = {
54
23
  interfaceName: '',
@@ -92,7 +61,7 @@ export class Matterbridge extends EventEmitter {
92
61
  shellySysUpdate: false,
93
62
  shellyMainUpdate: false,
94
63
  profile: getParameter('profile'),
95
- loggerLevel: "info" /* LogLevel.INFO */,
64
+ loggerLevel: "info",
96
65
  fileLogger: false,
97
66
  matterLoggerLevel: MatterLogLevel.INFO,
98
67
  matterFileLogger: false,
@@ -128,11 +97,9 @@ export class Matterbridge extends EventEmitter {
128
97
  plugins;
129
98
  devices;
130
99
  frontend = new Frontend(this);
131
- // Matterbridge storage
132
100
  nodeStorage;
133
101
  nodeContext;
134
102
  nodeStorageName = 'storage' + (getParameter('profile') ? '.' + getParameter('profile') : '');
135
- // Cleanup
136
103
  hasCleanupStarted = false;
137
104
  initialized = false;
138
105
  execRunningCount = 0;
@@ -145,70 +112,38 @@ export class Matterbridge extends EventEmitter {
145
112
  sigtermHandler;
146
113
  exceptionHandler;
147
114
  rejectionHandler;
148
- // Matter environment
149
115
  environment = Environment.default;
150
- // Matter storage
151
116
  matterStorageName = 'matterstorage' + (getParameter('profile') ? '.' + getParameter('profile') : '');
152
117
  matterStorageService;
153
118
  matterStorageManager;
154
119
  matterbridgeContext;
155
120
  mattercontrollerContext;
156
- // Matter parameters
157
- mdnsInterface; // matter server node mdnsInterface: e.g. 'eth0' or 'wlan0' or 'WiFi'
158
- ipv4address; // matter server node listeningAddressIpv4
159
- ipv6address; // matter server node listeningAddressIpv6
160
- port; // first server node port
161
- passcode; // first server node passcode
162
- discriminator; // first server node discriminator
121
+ mdnsInterface;
122
+ ipv4address;
123
+ ipv6address;
124
+ port;
125
+ passcode;
126
+ discriminator;
163
127
  serverNode;
164
128
  aggregatorNode;
165
129
  aggregatorVendorId = VendorId(getIntParameter('vendorId') ?? 0xfff1);
166
130
  aggregatorProductId = getIntParameter('productId') ?? 0x8000;
167
131
  static instance;
168
- // We load asyncronously so is private
169
132
  constructor() {
170
133
  super();
171
134
  }
172
- /**
173
- * Emits an event of the specified type with the provided arguments.
174
- *
175
- * @template K - The type of the event.
176
- * @param {K} eventName - The name of the event to emit.
177
- * @param {...MatterbridgeEvent[K]} args - The arguments to pass to the event listeners.
178
- * @returns {boolean} - Returns true if the event had listeners, false otherwise.
179
- */
180
135
  emit(eventName, ...args) {
181
136
  return super.emit(eventName, ...args);
182
137
  }
183
- /**
184
- * Registers an event listener for the specified event type.
185
- *
186
- * @template K - The type of the event.
187
- * @param {K} eventName - The name of the event to listen for.
188
- * @param {(...args: MatterbridgeEvent[K]) => void} listener - The callback function to invoke when the event is emitted.
189
- * @returns {this} - Returns the instance of the Matterbridge class.
190
- */
191
138
  on(eventName, listener) {
192
139
  return super.on(eventName, listener);
193
140
  }
194
- /**
195
- * Retrieves the list of Matterbridge devices.
196
- * @returns {MatterbridgeEndpoint[]} An array of MatterbridgeDevice objects.
197
- */
198
141
  getDevices() {
199
142
  return this.devices.array();
200
143
  }
201
- /**
202
- * Retrieves the list of registered plugins.
203
- * @returns {RegisteredPlugin[]} An array of RegisteredPlugin objects.
204
- */
205
144
  getPlugins() {
206
145
  return this.plugins.array();
207
146
  }
208
- /**
209
- * Set the logger logLevel for the Matterbridge classes.
210
- * @param {LogLevel} logLevel The logger logLevel to set.
211
- */
212
147
  async setLogLevel(logLevel) {
213
148
  if (this.log)
214
149
  this.log.logLevel = logLevel;
@@ -222,31 +157,19 @@ export class Matterbridge extends EventEmitter {
222
157
  for (const plugin of this.plugins) {
223
158
  if (!plugin.platform || !plugin.platform.log || !plugin.platform.config)
224
159
  continue;
225
- plugin.platform.log.logLevel = plugin.platform.config.debug === true ? "debug" /* LogLevel.DEBUG */ : this.log.logLevel;
226
- await plugin.platform.onChangeLoggerLevel(plugin.platform.config.debug === true ? "debug" /* LogLevel.DEBUG */ : this.log.logLevel);
227
- }
228
- // Set the global logger callback for the WebSocketServer to the common minimum logLevel
229
- let callbackLogLevel = "notice" /* LogLevel.NOTICE */;
230
- if (this.matterbridgeInformation.loggerLevel === "info" /* LogLevel.INFO */ || this.matterbridgeInformation.matterLoggerLevel === MatterLogLevel.INFO)
231
- callbackLogLevel = "info" /* LogLevel.INFO */;
232
- if (this.matterbridgeInformation.loggerLevel === "debug" /* LogLevel.DEBUG */ || this.matterbridgeInformation.matterLoggerLevel === MatterLogLevel.DEBUG)
233
- callbackLogLevel = "debug" /* LogLevel.DEBUG */;
160
+ plugin.platform.log.logLevel = plugin.platform.config.debug === true ? "debug" : this.log.logLevel;
161
+ await plugin.platform.onChangeLoggerLevel(plugin.platform.config.debug === true ? "debug" : this.log.logLevel);
162
+ }
163
+ let callbackLogLevel = "notice";
164
+ if (this.matterbridgeInformation.loggerLevel === "info" || this.matterbridgeInformation.matterLoggerLevel === MatterLogLevel.INFO)
165
+ callbackLogLevel = "info";
166
+ if (this.matterbridgeInformation.loggerLevel === "debug" || this.matterbridgeInformation.matterLoggerLevel === MatterLogLevel.DEBUG)
167
+ callbackLogLevel = "debug";
234
168
  AnsiLogger.setGlobalCallback(this.frontend.wssSendMessage.bind(this.frontend), callbackLogLevel);
235
169
  this.log.debug(`WebSocketServer logger global callback set to ${callbackLogLevel}`);
236
170
  }
237
- /** ***********************************************************************************************************************************/
238
- /** loadInstance() and cleanup() methods */
239
- /** ***********************************************************************************************************************************/
240
- /**
241
- * Loads an instance of the Matterbridge class.
242
- * If an instance already exists, return that instance.
243
- *
244
- * @param initialize - Whether to initialize the Matterbridge instance after loading.
245
- * @returns The loaded Matterbridge instance.
246
- */
247
171
  static async loadInstance(initialize = false) {
248
172
  if (!Matterbridge.instance) {
249
- // eslint-disable-next-line no-console
250
173
  if (hasParameter('debug'))
251
174
  console.log(GREEN + 'Creating a new instance of Matterbridge.', initialize ? 'Initializing...' : 'Not initializing...', rs);
252
175
  Matterbridge.instance = new Matterbridge();
@@ -255,14 +178,8 @@ export class Matterbridge extends EventEmitter {
255
178
  }
256
179
  return Matterbridge.instance;
257
180
  }
258
- /**
259
- * Call cleanup().
260
- * @deprecated This method is deprecated and is only used for jest tests.
261
- *
262
- */
263
181
  async destroyInstance() {
264
182
  this.log.info(`Destroy instance...`);
265
- // Save server nodes to close
266
183
  const servers = [];
267
184
  if (this.bridgeMode === 'bridge') {
268
185
  if (this.serverNode)
@@ -274,81 +191,55 @@ export class Matterbridge extends EventEmitter {
274
191
  servers.push(plugin.serverNode);
275
192
  }
276
193
  }
277
- // Cleanup
278
194
  await this.cleanup('destroying instance...', false);
279
- // Close servers mdns service
280
195
  this.log.info(`Dispose ${servers.length} MdnsService...`);
281
196
  for (const server of servers) {
282
197
  await server.env.get(MdnsService)[Symbol.asyncDispose]();
283
198
  this.log.info(`Closed ${server.id} MdnsService`);
284
199
  }
285
- // Wait for the cleanup to finish
286
200
  await new Promise((resolve) => {
287
201
  setTimeout(resolve, 1000);
288
202
  });
289
203
  }
290
- /**
291
- * Initializes the Matterbridge application.
292
- *
293
- * @remarks
294
- * This method performs the necessary setup and initialization steps for the Matterbridge application.
295
- * It displays the help information if the 'help' parameter is provided, sets up the logger, checks the
296
- * node version, registers signal handlers, initializes storage, and parses the command line.
297
- *
298
- * @returns A Promise that resolves when the initialization is complete.
299
- */
300
204
  async initialize() {
301
- // Set the restart mode
302
205
  if (hasParameter('service'))
303
206
  this.restartMode = 'service';
304
207
  if (hasParameter('docker'))
305
208
  this.restartMode = 'docker';
306
- // Set the matterbridge directory
307
209
  this.homeDirectory = getParameter('homedir') ?? os.homedir();
308
210
  this.matterbridgeDirectory = path.join(this.homeDirectory, '.matterbridge');
309
- // Setup the matter environment
310
211
  this.environment.vars.set('log.level', MatterLogLevel.INFO);
311
212
  this.environment.vars.set('log.format', MatterLogFormat.ANSI);
312
213
  this.environment.vars.set('path.root', path.join(this.matterbridgeDirectory, this.matterStorageName));
313
214
  this.environment.vars.set('runtime.signals', false);
314
215
  this.environment.vars.set('runtime.exitcode', false);
315
- // Create the matterbridge logger
316
- this.log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: hasParameter('debug') ? "debug" /* LogLevel.DEBUG */ : "info" /* LogLevel.INFO */ });
317
- // Register process handlers
216
+ this.log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4, logLevel: hasParameter('debug') ? "debug" : "info" });
318
217
  this.registerProcessHandlers();
319
- // Initialize nodeStorage and nodeContext
320
218
  try {
321
219
  this.log.debug(`Creating node storage manager: ${CYAN}${this.nodeStorageName}${db}`);
322
220
  this.nodeStorage = new NodeStorageManager({ dir: path.join(this.matterbridgeDirectory, this.nodeStorageName), writeQueue: false, expiredInterval: undefined, logging: false });
323
221
  this.log.debug('Creating node storage context for matterbridge');
324
222
  this.nodeContext = await this.nodeStorage.createStorage('matterbridge');
325
- // TODO: Remove this code when node-persist-manager is updated
326
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
327
223
  const keys = (await this.nodeStorage?.storage.keys());
328
224
  for (const key of keys) {
329
225
  this.log.debug(`Checking node storage manager key: ${CYAN}${key}${db}`);
330
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
331
226
  await this.nodeStorage?.storage.get(key);
332
227
  }
333
228
  const storages = await this.nodeStorage.getStorageNames();
334
229
  for (const storage of storages) {
335
230
  this.log.debug(`Checking storage: ${CYAN}${storage}${db}`);
336
231
  const nodeContext = await this.nodeStorage?.createStorage(storage);
337
- // TODO: Remove this code when node-persist-manager is updated
338
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
339
232
  const keys = (await nodeContext?.storage.keys());
340
233
  keys.forEach(async (key) => {
341
234
  this.log.debug(`Checking key: ${CYAN}${storage}:${key}${db}`);
342
235
  await nodeContext?.get(key);
343
236
  });
344
237
  }
345
- // Creating a backup of the node storage since it is not corrupted
346
238
  this.log.debug('Creating node storage backup...');
347
239
  await copyDirectory(path.join(this.matterbridgeDirectory, this.nodeStorageName), path.join(this.matterbridgeDirectory, this.nodeStorageName + '.backup'));
348
240
  this.log.debug('Created node storage backup');
349
241
  }
350
242
  catch (error) {
351
- // Restoring the backup of the node storage since it is corrupted
352
243
  this.log.error(`Error creating node storage manager and context: ${error instanceof Error ? error.message : error}`);
353
244
  if (hasParameter('norestore')) {
354
245
  this.log.fatal(`The matterbridge node storage is corrupted. Parameter -norestore found: exiting...`);
@@ -363,46 +254,41 @@ export class Matterbridge extends EventEmitter {
363
254
  this.log.fatal('Fatal error creating node storage manager and context for matterbridge');
364
255
  throw new Error('Fatal error creating node storage manager and context for matterbridge');
365
256
  }
366
- // Set the first port to use for the commissioning server (will be incremented in childbridge mode)
367
257
  this.port = getIntParameter('port') ?? (await this.nodeContext.get('matterport', 5540)) ?? 5540;
368
- // Set the first passcode to use for the commissioning server (will be incremented in childbridge mode)
369
258
  this.passcode = getIntParameter('passcode') ?? (await this.nodeContext.get('matterpasscode')) ?? PaseClient.generateRandomPasscode();
370
- // Set the first discriminator to use for the commissioning server (will be incremented in childbridge mode)
371
259
  this.discriminator = getIntParameter('discriminator') ?? (await this.nodeContext.get('matterdiscriminator')) ?? PaseClient.generateRandomDiscriminator();
372
260
  this.log.debug(`Initializing server node for Matterbridge... on port ${this.port} with passcode ${this.passcode} and discriminator ${this.discriminator}`);
373
- // Set matterbridge logger level (context: matterbridgeLogLevel)
374
261
  if (hasParameter('logger')) {
375
262
  const level = getParameter('logger');
376
263
  if (level === 'debug') {
377
- this.log.logLevel = "debug" /* LogLevel.DEBUG */;
264
+ this.log.logLevel = "debug";
378
265
  }
379
266
  else if (level === 'info') {
380
- this.log.logLevel = "info" /* LogLevel.INFO */;
267
+ this.log.logLevel = "info";
381
268
  }
382
269
  else if (level === 'notice') {
383
- this.log.logLevel = "notice" /* LogLevel.NOTICE */;
270
+ this.log.logLevel = "notice";
384
271
  }
385
272
  else if (level === 'warn') {
386
- this.log.logLevel = "warn" /* LogLevel.WARN */;
273
+ this.log.logLevel = "warn";
387
274
  }
388
275
  else if (level === 'error') {
389
- this.log.logLevel = "error" /* LogLevel.ERROR */;
276
+ this.log.logLevel = "error";
390
277
  }
391
278
  else if (level === 'fatal') {
392
- this.log.logLevel = "fatal" /* LogLevel.FATAL */;
279
+ this.log.logLevel = "fatal";
393
280
  }
394
281
  else {
395
282
  this.log.warn(`Invalid matterbridge logger level: ${level}. Using default level "info".`);
396
- this.log.logLevel = "info" /* LogLevel.INFO */;
283
+ this.log.logLevel = "info";
397
284
  }
398
285
  }
399
286
  else {
400
- this.log.logLevel = await this.nodeContext.get('matterbridgeLogLevel', "info" /* LogLevel.INFO */);
287
+ this.log.logLevel = await this.nodeContext.get('matterbridgeLogLevel', "info");
401
288
  }
402
289
  this.frontend.logLevel = this.log.logLevel;
403
290
  MatterbridgeEndpoint.logLevel = this.log.logLevel;
404
291
  this.matterbridgeInformation.loggerLevel = this.log.logLevel;
405
- // Create the file logger for matterbridge (context: matterbridgeFileLog)
406
292
  if (hasParameter('filelogger') || (await this.nodeContext.get('matterbridgeFileLog', false))) {
407
293
  AnsiLogger.setGlobalLogfile(path.join(this.matterbridgeDirectory, this.matterbrideLoggerFile), this.log.logLevel, true);
408
294
  this.matterbridgeInformation.fileLogger = true;
@@ -411,7 +297,6 @@ export class Matterbridge extends EventEmitter {
411
297
  this.log.debug(`Matterbridge logLevel: ${this.log.logLevel} fileLoger: ${this.matterbridgeInformation.fileLogger}.`);
412
298
  if (this.profile !== undefined)
413
299
  this.log.debug(`Matterbridge profile: ${this.profile}.`);
414
- // Set matter.js logger level, format and logger (context: matterLogLevel)
415
300
  if (hasParameter('matterlogger')) {
416
301
  const level = getParameter('matterlogger');
417
302
  if (level === 'debug') {
@@ -443,7 +328,6 @@ export class Matterbridge extends EventEmitter {
443
328
  Logger.format = MatterLogFormat.ANSI;
444
329
  Logger.setLogger('default', this.createMatterLogger());
445
330
  this.matterbridgeInformation.matterLoggerLevel = Logger.defaultLogLevel;
446
- // Create the file logger for matter.js (context: matterFileLog)
447
331
  if (hasParameter('matterfilelogger') || (await this.nodeContext.get('matterFileLog', false))) {
448
332
  this.matterbridgeInformation.matterFileLogger = true;
449
333
  Logger.addLogger('matterfilelogger', await this.createMatterFileLogger(path.join(this.matterbridgeDirectory, this.matterLoggerFile), true), {
@@ -452,7 +336,6 @@ export class Matterbridge extends EventEmitter {
452
336
  });
453
337
  }
454
338
  this.log.debug(`Matter logLevel: ${Logger.defaultLogLevel} fileLoger: ${this.matterbridgeInformation.matterFileLogger}.`);
455
- // Set the interface to use for matter server node mdnsInterface
456
339
  if (hasParameter('mdnsinterface')) {
457
340
  this.mdnsInterface = getParameter('mdnsinterface');
458
341
  }
@@ -461,7 +344,6 @@ export class Matterbridge extends EventEmitter {
461
344
  if (this.mdnsInterface === '')
462
345
  this.mdnsInterface = undefined;
463
346
  }
464
- // Validate mdnsInterface
465
347
  if (this.mdnsInterface) {
466
348
  const networkInterfaces = os.networkInterfaces();
467
349
  const availableInterfaces = Object.keys(networkInterfaces);
@@ -475,7 +357,6 @@ export class Matterbridge extends EventEmitter {
475
357
  }
476
358
  if (this.mdnsInterface)
477
359
  this.environment.vars.set('mdns.networkInterface', this.mdnsInterface);
478
- // Set the listeningAddressIpv4 for the matter commissioning server
479
360
  if (hasParameter('ipv4address')) {
480
361
  this.ipv4address = getParameter('ipv4address');
481
362
  }
@@ -484,7 +365,6 @@ export class Matterbridge extends EventEmitter {
484
365
  if (this.ipv4address === '')
485
366
  this.ipv4address = undefined;
486
367
  }
487
- // Set the listeningAddressIpv6 for the matter commissioning server
488
368
  if (hasParameter('ipv6address')) {
489
369
  this.ipv6address = getParameter('ipv6address');
490
370
  }
@@ -493,19 +373,14 @@ export class Matterbridge extends EventEmitter {
493
373
  if (this.ipv6address === '')
494
374
  this.ipv6address = undefined;
495
375
  }
496
- // Initialize PluginManager
497
376
  this.plugins = new PluginManager(this);
498
377
  await this.plugins.loadFromStorage();
499
378
  this.plugins.logLevel = this.log.logLevel;
500
- // Initialize DeviceManager
501
379
  this.devices = new DeviceManager(this, this.nodeContext);
502
380
  this.devices.logLevel = this.log.logLevel;
503
- // Get the plugins from node storage and create the plugins node storage contexts
504
381
  for (const plugin of this.plugins) {
505
382
  const packageJson = await this.plugins.parse(plugin);
506
383
  if (packageJson === null && !hasParameter('add') && !hasParameter('remove') && !hasParameter('enable') && !hasParameter('disable') && !hasParameter('reset') && !hasParameter('factoryreset')) {
507
- // Try to reinstall the plugin from npm (for Docker pull and external plugins)
508
- // We don't do this when the add and other parameters are set because we shut down the process after adding the plugin
509
384
  this.log.info(`Error parsing plugin ${plg}${plugin.name}${nf}. Trying to reinstall it from npm.`);
510
385
  try {
511
386
  await this.spawnCommand('npm', ['install', '-g', plugin.name, '--omit=dev', '--verbose']);
@@ -527,7 +402,6 @@ export class Matterbridge extends EventEmitter {
527
402
  await plugin.nodeContext.set('description', plugin.description);
528
403
  await plugin.nodeContext.set('author', plugin.author);
529
404
  }
530
- // Log system info and create .matterbridge directory
531
405
  await this.logNodeAndSystemInfo();
532
406
  this.log.notice(`Matterbridge version ${this.matterbridgeVersion} ` +
533
407
  `${hasParameter('bridge') || (!hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'bridge') ? 'mode bridge ' : ''}` +
@@ -535,7 +409,6 @@ export class Matterbridge extends EventEmitter {
535
409
  `${hasParameter('controller') ? 'mode controller ' : ''}` +
536
410
  `${this.restartMode !== '' ? 'restart mode ' + this.restartMode + ' ' : ''}` +
537
411
  `running on ${this.systemInformation.osType} (v.${this.systemInformation.osRelease}) platform ${this.systemInformation.osPlatform} arch ${this.systemInformation.osArch}`);
538
- // Check node version and throw error
539
412
  const minNodeVersion = 18;
540
413
  const nodeVersion = process.versions.node;
541
414
  const versionMajor = parseInt(nodeVersion.split('.')[0]);
@@ -543,15 +416,9 @@ export class Matterbridge extends EventEmitter {
543
416
  this.log.error(`Node version ${versionMajor} is not supported. Please upgrade to ${minNodeVersion} or above.`);
544
417
  throw new Error(`Node version ${versionMajor} is not supported. Please upgrade to ${minNodeVersion} or above.`);
545
418
  }
546
- // Parse command line
547
419
  await this.parseCommandLine();
548
420
  this.initialized = true;
549
421
  }
550
- /**
551
- * Parses the command line arguments and performs the corresponding actions.
552
- * @private
553
- * @returns {Promise<void>} A promise that resolves when the command line arguments have been processed, or the process exits.
554
- */
555
422
  async parseCommandLine() {
556
423
  if (hasParameter('help')) {
557
424
  this.log.info(`\nUsage: matterbridge [options]\n
@@ -663,7 +530,6 @@ export class Matterbridge extends EventEmitter {
663
530
  this.shutdown = true;
664
531
  return;
665
532
  }
666
- // Start the matter storage and create the matterbridge context
667
533
  try {
668
534
  await this.startMatterStorage();
669
535
  }
@@ -671,14 +537,12 @@ export class Matterbridge extends EventEmitter {
671
537
  this.log.fatal(`Fatal error creating matter storage: ${error instanceof Error ? error.message : error}`);
672
538
  throw new Error(`Fatal error creating matter storage: ${error instanceof Error ? error.message : error}`);
673
539
  }
674
- // Clear the matterbridge context if the reset parameter is set
675
540
  if (hasParameter('reset') && getParameter('reset') === undefined) {
676
541
  this.initialized = true;
677
542
  await this.shutdownProcessAndReset();
678
543
  this.shutdown = true;
679
544
  return;
680
545
  }
681
- // Clear matterbridge plugin context if the reset parameter is set
682
546
  if (hasParameter('reset') && getParameter('reset') !== undefined) {
683
547
  this.log.debug(`Reset plugin ${getParameter('reset')}`);
684
548
  const plugin = this.plugins.get(getParameter('reset'));
@@ -703,37 +567,30 @@ export class Matterbridge extends EventEmitter {
703
567
  this.shutdown = true;
704
568
  return;
705
569
  }
706
- // Initialize frontend
707
570
  if (getIntParameter('frontend') !== 0 || getIntParameter('frontend') === undefined)
708
571
  await this.frontend.start(getIntParameter('frontend'));
709
- // Check in 30 seconds the latest versions
710
572
  this.checkUpdateTimeout = setTimeout(async () => {
711
573
  const { checkUpdates } = await import('./update.js');
712
574
  checkUpdates(this);
713
575
  }, 30 * 1000).unref();
714
- // Check each 24 hours the latest versions
715
576
  this.checkUpdateInterval = setInterval(async () => {
716
577
  const { checkUpdates } = await import('./update.js');
717
578
  checkUpdates(this);
718
579
  }, 24 * 60 * 60 * 1000).unref();
719
- // Start the matterbridge in mode test
720
580
  if (hasParameter('test')) {
721
581
  this.bridgeMode = 'bridge';
722
582
  MatterbridgeEndpoint.bridgeMode = 'bridge';
723
583
  return;
724
584
  }
725
- // Start the matterbridge in mode controller
726
585
  if (hasParameter('controller')) {
727
586
  this.bridgeMode = 'controller';
728
587
  await this.startController();
729
588
  return;
730
589
  }
731
- // Check if the bridge mode is set and start matterbridge in bridge mode if not set
732
590
  if (!hasParameter('bridge') && !hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === '') {
733
591
  this.log.info('Setting default matterbridge start mode to bridge');
734
592
  await this.nodeContext?.set('bridgeMode', 'bridge');
735
593
  }
736
- // Start matterbridge in bridge mode
737
594
  if (hasParameter('bridge') || (!hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'bridge')) {
738
595
  this.bridgeMode = 'bridge';
739
596
  MatterbridgeEndpoint.bridgeMode = 'bridge';
@@ -741,7 +598,6 @@ export class Matterbridge extends EventEmitter {
741
598
  await this.startBridge();
742
599
  return;
743
600
  }
744
- // Start matterbridge in childbridge mode
745
601
  if (hasParameter('childbridge') || (!hasParameter('bridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'childbridge')) {
746
602
  this.bridgeMode = 'childbridge';
747
603
  MatterbridgeEndpoint.bridgeMode = 'childbridge';
@@ -750,20 +606,10 @@ export class Matterbridge extends EventEmitter {
750
606
  return;
751
607
  }
752
608
  }
753
- /**
754
- * Asynchronously loads and starts the registered plugins.
755
- *
756
- * This method is responsible for initializing and staarting all enabled plugins.
757
- * It ensures that each plugin is properly loaded and started before the bridge starts.
758
- *
759
- * @returns {Promise<void>} A promise that resolves when all plugins have been loaded and started.
760
- */
761
609
  async startPlugins() {
762
- // Check, load and start the plugins
763
610
  for (const plugin of this.plugins) {
764
611
  plugin.configJson = await this.plugins.loadConfig(plugin);
765
612
  plugin.schemaJson = await this.plugins.loadSchema(plugin);
766
- // Check if the plugin is available
767
613
  if (!(await this.plugins.resolve(plugin.path))) {
768
614
  this.log.error(`Plugin ${plg}${plugin.name}${er} not found or not validated. Disabling it.`);
769
615
  plugin.enabled = false;
@@ -783,26 +629,20 @@ export class Matterbridge extends EventEmitter {
783
629
  plugin.addedDevices = undefined;
784
630
  plugin.qrPairingCode = undefined;
785
631
  plugin.manualPairingCode = undefined;
786
- this.plugins.load(plugin, true, 'Matterbridge is starting'); // No await do it asyncronously
632
+ this.plugins.load(plugin, true, 'Matterbridge is starting');
787
633
  }
788
634
  this.frontend.wssSendRefreshRequired();
789
635
  }
790
- /**
791
- * Registers the process handlers for uncaughtException, unhandledRejection, SIGINT and SIGTERM.
792
- * When either of these signals are received, the cleanup method is called with an appropriate message.
793
- */
794
636
  registerProcessHandlers() {
795
637
  this.log.debug(`Registering uncaughtException and unhandledRejection handlers...`);
796
638
  process.removeAllListeners('uncaughtException');
797
639
  process.removeAllListeners('unhandledRejection');
798
640
  this.exceptionHandler = async (error) => {
799
641
  this.log.error('Unhandled Exception detected at:', error.stack || error, rs);
800
- // await this.cleanup('Unhandled Exception detected, cleaning up...');
801
642
  };
802
643
  process.on('uncaughtException', this.exceptionHandler);
803
644
  this.rejectionHandler = async (reason, promise) => {
804
645
  this.log.error('Unhandled Rejection detected at:', promise, 'reason:', reason instanceof Error ? reason.stack : reason, rs);
805
- // await this.cleanup('Unhandled Rejection detected, cleaning up...');
806
646
  };
807
647
  process.on('unhandledRejection', this.rejectionHandler);
808
648
  this.log.debug(`Registering SIGINT and SIGTERM signal handlers...`);
@@ -815,9 +655,6 @@ export class Matterbridge extends EventEmitter {
815
655
  };
816
656
  process.on('SIGTERM', this.sigtermHandler);
817
657
  }
818
- /**
819
- * Deregisters the process uncaughtException, unhandledRejection, SIGINT and SIGTERM signal handlers.
820
- */
821
658
  deregisterProcesslHandlers() {
822
659
  this.log.debug(`Deregistering uncaughtException and unhandledRejection handlers...`);
823
660
  if (this.exceptionHandler)
@@ -834,17 +671,12 @@ export class Matterbridge extends EventEmitter {
834
671
  process.off('SIGTERM', this.sigtermHandler);
835
672
  this.sigtermHandler = undefined;
836
673
  }
837
- /**
838
- * Logs the node and system information.
839
- */
840
674
  async logNodeAndSystemInfo() {
841
- // IP address information
842
675
  const networkInterfaces = os.networkInterfaces();
843
676
  this.systemInformation.interfaceName = '';
844
677
  this.systemInformation.ipv4Address = '';
845
678
  this.systemInformation.ipv6Address = '';
846
679
  for (const [interfaceName, interfaceDetails] of Object.entries(networkInterfaces)) {
847
- // this.log.debug(`Checking interface: '${interfaceName}' for '${this.mdnsInterface}'`);
848
680
  if (this.mdnsInterface && interfaceName !== this.mdnsInterface)
849
681
  continue;
850
682
  if (!interfaceDetails) {
@@ -870,22 +702,19 @@ export class Matterbridge extends EventEmitter {
870
702
  break;
871
703
  }
872
704
  }
873
- // Node information
874
705
  this.systemInformation.nodeVersion = process.versions.node;
875
706
  const versionMajor = parseInt(this.systemInformation.nodeVersion.split('.')[0]);
876
707
  const versionMinor = parseInt(this.systemInformation.nodeVersion.split('.')[1]);
877
708
  const versionPatch = parseInt(this.systemInformation.nodeVersion.split('.')[2]);
878
- // Host system information
879
709
  this.systemInformation.hostname = os.hostname();
880
710
  this.systemInformation.user = os.userInfo().username;
881
- this.systemInformation.osType = os.type(); // "Windows_NT", "Darwin", etc.
882
- this.systemInformation.osRelease = os.release(); // Kernel version
883
- this.systemInformation.osPlatform = os.platform(); // "win32", "linux", "darwin", etc.
884
- this.systemInformation.osArch = os.arch(); // "x64", "arm", etc.
885
- this.systemInformation.totalMemory = (os.totalmem() / 1024 / 1024 / 1024).toFixed(2) + ' GB'; // Convert to GB
886
- this.systemInformation.freeMemory = (os.freemem() / 1024 / 1024 / 1024).toFixed(2) + ' GB'; // Convert to GB
887
- this.systemInformation.systemUptime = (os.uptime() / 60 / 60).toFixed(2) + ' hours'; // Convert to hours
888
- // Log the system information
711
+ this.systemInformation.osType = os.type();
712
+ this.systemInformation.osRelease = os.release();
713
+ this.systemInformation.osPlatform = os.platform();
714
+ this.systemInformation.osArch = os.arch();
715
+ this.systemInformation.totalMemory = (os.totalmem() / 1024 / 1024 / 1024).toFixed(2) + ' GB';
716
+ this.systemInformation.freeMemory = (os.freemem() / 1024 / 1024 / 1024).toFixed(2) + ' GB';
717
+ this.systemInformation.systemUptime = (os.uptime() / 60 / 60).toFixed(2) + ' hours';
889
718
  this.log.debug('Host System Information:');
890
719
  this.log.debug(`- Hostname: ${this.systemInformation.hostname}`);
891
720
  this.log.debug(`- User: ${this.systemInformation.user}`);
@@ -901,20 +730,16 @@ export class Matterbridge extends EventEmitter {
901
730
  this.log.debug(`- Total Memory: ${this.systemInformation.totalMemory}`);
902
731
  this.log.debug(`- Free Memory: ${this.systemInformation.freeMemory}`);
903
732
  this.log.debug(`- System Uptime: ${this.systemInformation.systemUptime}`);
904
- // Home directory
905
733
  this.homeDirectory = getParameter('homedir') ?? os.homedir();
906
734
  this.matterbridgeInformation.homeDirectory = this.homeDirectory;
907
735
  this.log.debug(`Home Directory: ${this.homeDirectory}`);
908
- // Package root directory
909
736
  const { fileURLToPath } = await import('node:url');
910
737
  const currentFileDirectory = path.dirname(fileURLToPath(import.meta.url));
911
738
  this.rootDirectory = path.resolve(currentFileDirectory, '../');
912
739
  this.matterbridgeInformation.rootDirectory = this.rootDirectory;
913
740
  this.log.debug(`Root Directory: ${this.rootDirectory}`);
914
- // Global node_modules directory
915
741
  if (this.nodeContext)
916
742
  this.globalModulesDirectory = this.matterbridgeInformation.globalModulesDirectory = await this.nodeContext.get('globalModulesDirectory', '');
917
- // First run of Matterbridge so the node storage is empty
918
743
  if (this.globalModulesDirectory === '') {
919
744
  try {
920
745
  this.execRunningCount++;
@@ -930,20 +755,6 @@ export class Matterbridge extends EventEmitter {
930
755
  }
931
756
  else
932
757
  this.log.debug(`Global node_modules Directory: ${this.globalModulesDirectory}`);
933
- /* removed cause is too expensive for the shelly board and not really needed. Why should it change the globalModulesDirectory?
934
- else {
935
- this.getGlobalNodeModules()
936
- .then(async (globalModulesDirectory) => {
937
- this.globalModulesDirectory = globalModulesDirectory;
938
- this.matterbridgeInformation.globalModulesDirectory = this.globalModulesDirectory;
939
- this.log.debug(`Global node_modules Directory: ${this.globalModulesDirectory}`);
940
- await this.nodeContext?.set<string>('globalModulesDirectory', this.globalModulesDirectory);
941
- })
942
- .catch((error) => {
943
- this.log.error(`Error getting global node_modules directory: ${error}`);
944
- });
945
- }*/
946
- // Create the data directory .matterbridge in the home directory
947
758
  this.matterbridgeDirectory = path.join(this.homeDirectory, '.matterbridge');
948
759
  this.matterbridgeInformation.matterbridgeDirectory = this.matterbridgeDirectory;
949
760
  try {
@@ -967,7 +778,6 @@ export class Matterbridge extends EventEmitter {
967
778
  }
968
779
  }
969
780
  this.log.debug(`Matterbridge Directory: ${this.matterbridgeDirectory}`);
970
- // Create the plugin directory Matterbridge in the home directory
971
781
  this.matterbridgePluginDirectory = path.join(this.homeDirectory, 'Matterbridge');
972
782
  this.matterbridgeInformation.matterbridgePluginDirectory = this.matterbridgePluginDirectory;
973
783
  try {
@@ -991,68 +801,50 @@ export class Matterbridge extends EventEmitter {
991
801
  }
992
802
  }
993
803
  this.log.debug(`Matterbridge Plugin Directory: ${this.matterbridgePluginDirectory}`);
994
- // Matterbridge version
995
804
  const packageJson = JSON.parse(await fs.readFile(path.join(this.rootDirectory, 'package.json'), 'utf-8'));
996
805
  this.matterbridgeVersion = this.matterbridgeLatestVersion = packageJson.version;
997
806
  this.matterbridgeInformation.matterbridgeVersion = this.matterbridgeInformation.matterbridgeLatestVersion = this.matterbridgeVersion;
998
807
  this.log.debug(`Matterbridge Version: ${this.matterbridgeVersion}`);
999
- // Matterbridge latest version
1000
808
  if (this.nodeContext)
1001
809
  this.matterbridgeLatestVersion = await this.nodeContext.get('matterbridgeLatestVersion', this.matterbridgeVersion);
1002
810
  this.log.debug(`Matterbridge Latest Version: ${this.matterbridgeLatestVersion}`);
1003
- // this.getMatterbridgeLatestVersion();
1004
- // Current working directory
1005
811
  const currentDir = process.cwd();
1006
812
  this.log.debug(`Current Working Directory: ${currentDir}`);
1007
- // Command line arguments (excluding 'node' and the script name)
1008
813
  const cmdArgs = process.argv.slice(2).join(' ');
1009
814
  this.log.debug(`Command Line Arguments: ${cmdArgs}`);
1010
815
  }
1011
- /**
1012
- * Creates a MatterLogger function to show the matter.js log messages in AnsiLogger (for the frontend).
1013
- *
1014
- * @returns {Function} The MatterLogger function.
1015
- */
1016
816
  createMatterLogger() {
1017
- const matterLogger = new AnsiLogger({ logName: 'Matter', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: "debug" /* LogLevel.DEBUG */ });
817
+ const matterLogger = new AnsiLogger({ logName: 'Matter', logTimestampFormat: 4, logLevel: "debug" });
1018
818
  return (_level, formattedLog) => {
1019
819
  const logger = formattedLog.slice(44, 44 + 20).trim();
1020
820
  const message = formattedLog.slice(65);
1021
821
  matterLogger.logName = logger;
1022
822
  switch (_level) {
1023
823
  case MatterLogLevel.DEBUG:
1024
- matterLogger.log("debug" /* LogLevel.DEBUG */, message);
824
+ matterLogger.log("debug", message);
1025
825
  break;
1026
826
  case MatterLogLevel.INFO:
1027
- matterLogger.log("info" /* LogLevel.INFO */, message);
827
+ matterLogger.log("info", message);
1028
828
  break;
1029
829
  case MatterLogLevel.NOTICE:
1030
- matterLogger.log("notice" /* LogLevel.NOTICE */, message);
830
+ matterLogger.log("notice", message);
1031
831
  break;
1032
832
  case MatterLogLevel.WARN:
1033
- matterLogger.log("warn" /* LogLevel.WARN */, message);
833
+ matterLogger.log("warn", message);
1034
834
  break;
1035
835
  case MatterLogLevel.ERROR:
1036
- matterLogger.log("error" /* LogLevel.ERROR */, message);
836
+ matterLogger.log("error", message);
1037
837
  break;
1038
838
  case MatterLogLevel.FATAL:
1039
- matterLogger.log("fatal" /* LogLevel.FATAL */, message);
839
+ matterLogger.log("fatal", message);
1040
840
  break;
1041
841
  default:
1042
- matterLogger.log("debug" /* LogLevel.DEBUG */, message);
842
+ matterLogger.log("debug", message);
1043
843
  break;
1044
844
  }
1045
845
  };
1046
846
  }
1047
- /**
1048
- * Creates a Matter File Logger.
1049
- *
1050
- * @param {string} filePath - The path to the log file.
1051
- * @param {boolean} [unlink=false] - Whether to unlink the log file before creating a new one.
1052
- * @returns {Function} - A function that logs formatted messages to the log file.
1053
- */
1054
847
  async createMatterFileLogger(filePath, unlink = false) {
1055
- // 2024-08-21 08:55:19.488 DEBUG InteractionMessenger Sending DataReport chunk with 28 attributes and 0 events: 1004 bytes
1056
848
  let fileSize = 0;
1057
849
  if (unlink) {
1058
850
  try {
@@ -1101,21 +893,12 @@ export class Matterbridge extends EventEmitter {
1101
893
  }
1102
894
  };
1103
895
  }
1104
- /**
1105
- * Restarts the process by exiting the current instance and loading a new instance.
1106
- */
1107
896
  async restartProcess() {
1108
897
  await this.cleanup('restarting...', true);
1109
898
  }
1110
- /**
1111
- * Shut down the process by exiting the current process.
1112
- */
1113
899
  async shutdownProcess() {
1114
900
  await this.cleanup('shutting down...', false);
1115
901
  }
1116
- /**
1117
- * Update matterbridge and and shut down the process.
1118
- */
1119
902
  async updateProcess() {
1120
903
  this.log.info('Updating matterbridge...');
1121
904
  try {
@@ -1128,72 +911,51 @@ export class Matterbridge extends EventEmitter {
1128
911
  this.frontend.wssSendRestartRequired();
1129
912
  await this.cleanup('updating...', false);
1130
913
  }
1131
- /**
1132
- * Unregister all devices and shut down the process.
1133
- */
1134
914
  async unregisterAndShutdownProcess() {
1135
915
  this.log.info('Unregistering all devices and shutting down...');
1136
916
  for (const plugin of this.plugins) {
1137
- await this.removeAllBridgedEndpoints(plugin.name);
917
+ await this.removeAllBridgedEndpoints(plugin.name, 200);
1138
918
  }
1139
919
  this.log.debug('Waiting for the MessageExchange to finish...');
1140
- await new Promise((resolve) => setTimeout(resolve, 1000)); // Wait 1 second for MessageExchange to finish
920
+ await new Promise((resolve) => setTimeout(resolve, 1000));
1141
921
  this.log.debug('Cleaning up and shutting down...');
1142
922
  await this.cleanup('unregistered all devices and shutting down...', false);
1143
923
  }
1144
- /**
1145
- * Reset commissioning and shut down the process.
1146
- */
1147
924
  async shutdownProcessAndReset() {
1148
925
  await this.cleanup('shutting down with reset...', false);
1149
926
  }
1150
- /**
1151
- * Factory reset and shut down the process.
1152
- */
1153
927
  async shutdownProcessAndFactoryReset() {
1154
928
  await this.cleanup('shutting down with factory reset...', false);
1155
929
  }
1156
- /**
1157
- * Cleans up the Matterbridge instance.
1158
- * @param message - The cleanup message.
1159
- * @param restart - Indicates whether to restart the instance after cleanup. Default is `false`.
1160
- * @returns A promise that resolves when the cleanup is completed.
1161
- */
1162
930
  async cleanup(message, restart = false) {
1163
931
  if (this.initialized && !this.hasCleanupStarted) {
1164
932
  this.hasCleanupStarted = true;
1165
933
  this.log.info(message);
1166
- // Clear the start matter interval
1167
934
  if (this.startMatterInterval) {
1168
935
  clearInterval(this.startMatterInterval);
1169
936
  this.startMatterInterval = undefined;
1170
937
  this.log.debug('Start matter interval cleared');
1171
938
  }
1172
- // Clear the check update timeout
1173
939
  if (this.checkUpdateTimeout) {
1174
940
  clearInterval(this.checkUpdateTimeout);
1175
941
  this.checkUpdateTimeout = undefined;
1176
942
  this.log.debug('Check update timeout cleared');
1177
943
  }
1178
- // Clear the check update interval
1179
944
  if (this.checkUpdateInterval) {
1180
945
  clearInterval(this.checkUpdateInterval);
1181
946
  this.checkUpdateInterval = undefined;
1182
947
  this.log.debug('Check update interval cleared');
1183
948
  }
1184
- // Clear the configure timeout
1185
949
  if (this.configureTimeout) {
1186
950
  clearTimeout(this.configureTimeout);
1187
951
  this.configureTimeout = undefined;
1188
952
  this.log.debug('Matterbridge configure timeout cleared');
1189
953
  }
1190
- // Clear the reachability timeout
1191
954
  if (this.reachabilityTimeout) {
1192
955
  clearTimeout(this.reachabilityTimeout);
1193
956
  this.reachabilityTimeout = undefined;
1194
957
  this.log.debug('Matterbridge reachability timeout cleared');
1195
958
  }
1196
- // Calling the shutdown method of each plugin and clear the plugins reachability timeout
1197
959
  for (const plugin of this.plugins) {
1198
960
  if (!plugin.enabled || plugin.error)
1199
961
  continue;
@@ -1204,10 +966,9 @@ export class Matterbridge extends EventEmitter {
1204
966
  this.log.debug(`Plugin ${plg}${plugin.name}${db} reachability timeout cleared`);
1205
967
  }
1206
968
  }
1207
- // Stopping matter server nodes
1208
969
  this.log.notice(`Stopping matter server nodes in ${this.bridgeMode} mode...`);
1209
970
  this.log.debug('Waiting for the MessageExchange to finish...');
1210
- await new Promise((resolve) => setTimeout(resolve, 1000)); // Wait 1 second for MessageExchange to finish
971
+ await new Promise((resolve) => setTimeout(resolve, 1000));
1211
972
  if (this.bridgeMode === 'bridge') {
1212
973
  if (this.serverNode) {
1213
974
  await this.stopServerNode(this.serverNode);
@@ -1223,7 +984,6 @@ export class Matterbridge extends EventEmitter {
1223
984
  }
1224
985
  }
1225
986
  this.log.notice('Stopped matter server nodes');
1226
- // Matter commisioning reset
1227
987
  if (message === 'shutting down with reset...') {
1228
988
  this.log.info('Resetting Matterbridge commissioning information...');
1229
989
  await this.matterStorageManager?.createContext('events')?.clearAll();
@@ -1233,37 +993,17 @@ export class Matterbridge extends EventEmitter {
1233
993
  await this.matterbridgeContext?.clearAll();
1234
994
  this.log.info('Matter storage reset done! Remove the bridge from the controller.');
1235
995
  }
1236
- // Stop matter storage
1237
996
  await this.stopMatterStorage();
1238
- // Stop the frontend
1239
997
  await this.frontend.stop();
1240
- // Remove the matterfilelogger
1241
998
  try {
1242
999
  Logger.removeLogger('matterfilelogger');
1243
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1244
1000
  }
1245
1001
  catch (error) {
1246
- // this.log.debug(`Error removing the matterfilelogger for file ${CYAN}${path.join(this.matterbridgeDirectory, this.matterLoggerFile)}${er}: ${error instanceof Error ? error.message : error}`);
1247
1002
  }
1248
- // Serialize registeredDevices
1249
1003
  if (this.nodeStorage && this.nodeContext) {
1250
- /*
1251
- TODO: Implement serialization of registered devices in edge mode
1252
- this.log.info('Saving registered devices...');
1253
- const serializedRegisteredDevices: SerializedMatterbridgeEndpoint[] = [];
1254
- this.devices.forEach(async (device) => {
1255
- const serializedMatterbridgeDevice = MatterbridgeEndpoint.serialize(device);
1256
- // this.log.info(`- ${serializedMatterbridgeDevice.deviceName}${rs}\n`, serializedMatterbridgeDevice);
1257
- if (serializedMatterbridgeDevice) serializedRegisteredDevices.push(serializedMatterbridgeDevice);
1258
- });
1259
- await this.nodeContext.set<SerializedMatterbridgeEndpoint[]>('devices', serializedRegisteredDevices);
1260
- this.log.info(`Saved registered devices (${serializedRegisteredDevices?.length})`);
1261
- */
1262
- // Clear nodeContext and nodeStorage (they just need 1000ms to write the data to disk)
1263
1004
  this.log.debug(`Closing node storage context for ${plg}Matterbridge${db}...`);
1264
1005
  await this.nodeContext.close();
1265
1006
  this.nodeContext = undefined;
1266
- // Clear nodeContext for each plugin (they just need 1000ms to write the data to disk)
1267
1007
  for (const plugin of this.plugins) {
1268
1008
  if (plugin.nodeContext) {
1269
1009
  this.log.debug(`Closing node storage context for plugin ${plg}${plugin.name}${db}...`);
@@ -1280,10 +1020,8 @@ export class Matterbridge extends EventEmitter {
1280
1020
  }
1281
1021
  this.plugins.clear();
1282
1022
  this.devices.clear();
1283
- // Factory reset
1284
1023
  if (message === 'shutting down with factory reset...') {
1285
1024
  try {
1286
- // Delete old matter storage file and backup
1287
1025
  const file = path.join(this.matterbridgeDirectory, 'matterbridge' + (getParameter('profile') ? '.' + getParameter('profile') : '') + '.json');
1288
1026
  this.log.info(`Unlinking old matter storage file: ${file}`);
1289
1027
  await fs.unlink(file);
@@ -1297,7 +1035,6 @@ export class Matterbridge extends EventEmitter {
1297
1035
  }
1298
1036
  }
1299
1037
  try {
1300
- // Delete matter node storage directory with its subdirectories and backup
1301
1038
  const dir = path.join(this.matterbridgeDirectory, 'matterstorage' + (getParameter('profile') ? '.' + getParameter('profile') : ''));
1302
1039
  this.log.info(`Removing matter node storage directory: ${dir}`);
1303
1040
  await fs.rm(dir, { recursive: true });
@@ -1311,7 +1048,6 @@ export class Matterbridge extends EventEmitter {
1311
1048
  }
1312
1049
  }
1313
1050
  try {
1314
- // Delete node storage directory with its subdirectories and backup
1315
1051
  const dir = path.join(this.matterbridgeDirectory, 'storage' + (getParameter('profile') ? '.' + getParameter('profile') : ''));
1316
1052
  this.log.info(`Removing storage directory: ${dir}`);
1317
1053
  await fs.rm(dir, { recursive: true });
@@ -1326,13 +1062,12 @@ export class Matterbridge extends EventEmitter {
1326
1062
  }
1327
1063
  this.log.info('Factory reset done! Remove all paired fabrics from the controllers.');
1328
1064
  }
1329
- // Deregisters the process handlers
1330
1065
  this.deregisterProcesslHandlers();
1331
1066
  if (restart) {
1332
1067
  if (message === 'updating...') {
1333
1068
  this.log.info('Cleanup completed. Updating...');
1334
1069
  Matterbridge.instance = undefined;
1335
- this.emit('update'); // Restart the process but the update has been done before. TODO move all updates to the cli
1070
+ this.emit('update');
1336
1071
  }
1337
1072
  else if (message === 'restarting...') {
1338
1073
  this.log.info('Cleanup completed. Restarting...');
@@ -1352,14 +1087,6 @@ export class Matterbridge extends EventEmitter {
1352
1087
  this.log.debug('Cleanup already started...');
1353
1088
  }
1354
1089
  }
1355
- /**
1356
- * Creates and configures the server node for an accessory plugin for a given device.
1357
- *
1358
- * @param {RegisteredPlugin} plugin - The plugin to configure.
1359
- * @param {MatterbridgeEndpoint} device - The device to associate with the plugin.
1360
- * @param {boolean} [start=false] - Whether to start the server node after adding the device.
1361
- * @returns {Promise<void>} A promise that resolves when the server node for the accessory plugin is created and configured.
1362
- */
1363
1090
  async createAccessoryPlugin(plugin, device, start = false) {
1364
1091
  if (!plugin.locked && device.deviceName && device.vendorId && device.productId && device.vendorName && device.productName) {
1365
1092
  plugin.locked = true;
@@ -1372,13 +1099,6 @@ export class Matterbridge extends EventEmitter {
1372
1099
  await this.startServerNode(plugin.serverNode);
1373
1100
  }
1374
1101
  }
1375
- /**
1376
- * Creates and configures the server node for a dynamic plugin.
1377
- *
1378
- * @param {RegisteredPlugin} plugin - The plugin to configure.
1379
- * @param {boolean} [start=false] - Whether to start the server node after adding the aggregator node.
1380
- * @returns {Promise<void>} A promise that resolves when the server node for the dynamic plugin is created and configured.
1381
- */
1382
1102
  async createDynamicPlugin(plugin, start = false) {
1383
1103
  if (!plugin.locked) {
1384
1104
  plugin.locked = true;
@@ -1390,13 +1110,7 @@ export class Matterbridge extends EventEmitter {
1390
1110
  await this.startServerNode(plugin.serverNode);
1391
1111
  }
1392
1112
  }
1393
- /**
1394
- * Starts the Matterbridge in bridge mode.
1395
- * @private
1396
- * @returns {Promise<void>} A promise that resolves when the Matterbridge is started.
1397
- */
1398
1113
  async startBridge() {
1399
- // Plugins are configured by a timer when matter server is started and plugin.configured is set to true
1400
1114
  if (!this.matterStorageManager)
1401
1115
  throw new Error('No storage manager initialized');
1402
1116
  if (!this.matterbridgeContext)
@@ -1433,9 +1147,7 @@ export class Matterbridge extends EventEmitter {
1433
1147
  clearInterval(this.startMatterInterval);
1434
1148
  this.startMatterInterval = undefined;
1435
1149
  this.log.debug('Cleared startMatterInterval interval for Matterbridge');
1436
- // Start the Matter server node
1437
1150
  this.startServerNode(this.serverNode);
1438
- // Configure the plugins
1439
1151
  this.configureTimeout = setTimeout(async () => {
1440
1152
  for (const plugin of this.plugins) {
1441
1153
  if (!plugin.enabled || !plugin.loaded || !plugin.started || plugin.error)
@@ -1450,7 +1162,6 @@ export class Matterbridge extends EventEmitter {
1450
1162
  }
1451
1163
  this.frontend.wssSendRefreshRequired();
1452
1164
  }, 30 * 1000);
1453
- // Setting reachability to true
1454
1165
  this.reachabilityTimeout = setTimeout(() => {
1455
1166
  this.log.info(`Setting reachability to true for ${plg}Matterbridge${db}`);
1456
1167
  if (this.aggregatorNode)
@@ -1459,11 +1170,6 @@ export class Matterbridge extends EventEmitter {
1459
1170
  }, 60 * 1000);
1460
1171
  }, 1000);
1461
1172
  }
1462
- /**
1463
- * Starts the Matterbridge in childbridge mode.
1464
- * @private
1465
- * @returns {Promise<void>} A promise that resolves when the Matterbridge is started.
1466
- */
1467
1173
  async startChildbridge() {
1468
1174
  if (!this.matterStorageManager)
1469
1175
  throw new Error('No storage manager initialized');
@@ -1507,13 +1213,12 @@ export class Matterbridge extends EventEmitter {
1507
1213
  clearInterval(this.startMatterInterval);
1508
1214
  this.startMatterInterval = undefined;
1509
1215
  this.log.debug('Cleared startMatterInterval interval in childbridge mode');
1510
- // Configure the plugins
1511
1216
  this.configureTimeout = setTimeout(async () => {
1512
1217
  for (const plugin of this.plugins) {
1513
1218
  if (!plugin.enabled || !plugin.loaded || !plugin.started || plugin.error)
1514
1219
  continue;
1515
1220
  try {
1516
- await this.plugins.configure(plugin); // TODO No await do it in parallel
1221
+ await this.plugins.configure(plugin);
1517
1222
  }
1518
1223
  catch (error) {
1519
1224
  plugin.error = true;
@@ -1541,9 +1246,7 @@ export class Matterbridge extends EventEmitter {
1541
1246
  this.log.error(`Node storage context not found for plugin ${plg}${plugin.name}${er}`);
1542
1247
  continue;
1543
1248
  }
1544
- // Start the Matter server node
1545
1249
  this.startServerNode(plugin.serverNode);
1546
- // Setting reachability to true
1547
1250
  plugin.reachabilityTimeout = setTimeout(() => {
1548
1251
  this.log.info(`Setting reachability to true for ${plg}${plugin.name}${db} type ${plugin.type} server node ${plugin.serverNode !== undefined} aggragator node ${plugin.aggregatorNode !== undefined} device ${plugin.device !== undefined}`);
1549
1252
  if (plugin.type === 'DynamicPlatform' && plugin.aggregatorNode)
@@ -1553,219 +1256,9 @@ export class Matterbridge extends EventEmitter {
1553
1256
  }
1554
1257
  }, 1000);
1555
1258
  }
1556
- /**
1557
- * Starts the Matterbridge controller.
1558
- * @private
1559
- * @returns {Promise<void>} A promise that resolves when the Matterbridge is started.
1560
- */
1561
1259
  async startController() {
1562
- /*
1563
- if (!this.storageManager) {
1564
- this.log.error('No storage manager initialized');
1565
- await this.cleanup('No storage manager initialized');
1566
- return;
1567
- }
1568
- this.log.info('Creating context: mattercontrollerContext');
1569
- this.mattercontrollerContext = this.storageManager.createContext('mattercontrollerContext');
1570
- if (!this.mattercontrollerContext) {
1571
- this.log.error('No storage context mattercontrollerContext initialized');
1572
- await this.cleanup('No storage context mattercontrollerContext initialized');
1573
- return;
1574
- }
1575
-
1576
- this.log.debug('Starting matterbridge in mode', this.bridgeMode);
1577
- this.matterServer = await this.createMatterServer(this.storageManager);
1578
- this.log.info('Creating matter commissioning controller');
1579
- this.commissioningController = new CommissioningController({
1580
- autoConnect: false,
1581
- });
1582
- this.log.info('Adding matter commissioning controller to matter server');
1583
- await this.matterServer.addCommissioningController(this.commissioningController);
1584
-
1585
- this.log.info('Starting matter server');
1586
- await this.matterServer.start();
1587
- this.log.info('Matter server started');
1588
-
1589
- if (hasParameter('pairingcode')) {
1590
- this.log.info('Pairing device with pairingcode:', getParameter('pairingcode'));
1591
- const pairingCode = getParameter('pairingcode');
1592
- const ip = this.mattercontrollerContext.has('ip') ? this.mattercontrollerContext.get<string>('ip') : undefined;
1593
- const port = this.mattercontrollerContext.has('port') ? this.mattercontrollerContext.get<number>('port') : undefined;
1594
-
1595
- let longDiscriminator, setupPin, shortDiscriminator;
1596
- if (pairingCode !== undefined) {
1597
- const pairingCodeCodec = ManualPairingCodeCodec.decode(pairingCode);
1598
- shortDiscriminator = pairingCodeCodec.shortDiscriminator;
1599
- longDiscriminator = undefined;
1600
- setupPin = pairingCodeCodec.passcode;
1601
- this.log.info(`Data extracted from pairing code: ${Logger.toJSON(pairingCodeCodec)}`);
1602
- } else {
1603
- longDiscriminator = await this.mattercontrollerContext.get('longDiscriminator', 3840);
1604
- if (longDiscriminator > 4095) throw new Error('Discriminator value must be less than 4096');
1605
- setupPin = this.mattercontrollerContext.get('pin', 20202021);
1606
- }
1607
- if ((shortDiscriminator === undefined && longDiscriminator === undefined) || setupPin === undefined) {
1608
- throw new Error('Please specify the longDiscriminator of the device to commission with -longDiscriminator or provide a valid passcode with -passcode');
1609
- }
1610
-
1611
- const commissioningOptions: ControllerCommissioningFlowOptions = {
1612
- regulatoryLocation: GeneralCommissioning.RegulatoryLocationType.IndoorOutdoor,
1613
- regulatoryCountryCode: 'XX',
1614
- };
1615
- const options = {
1616
- commissioning: commissioningOptions,
1617
- discovery: {
1618
- knownAddress: ip !== undefined && port !== undefined ? { ip, port, type: 'udp' } : undefined,
1619
- identifierData: longDiscriminator !== undefined ? { longDiscriminator } : shortDiscriminator !== undefined ? { shortDiscriminator } : {},
1620
- },
1621
- passcode: setupPin,
1622
- } as NodeCommissioningOptions;
1623
- this.log.info('Commissioning with options:', options);
1624
- const nodeId = await this.commissioningController.commissionNode(options);
1625
- this.log.info(`Commissioning successfully done with nodeId: ${nodeId}`);
1626
- this.log.info('ActiveSessionInformation:', this.commissioningController.getActiveSessionInformation());
1627
- } // (hasParameter('pairingcode'))
1628
-
1629
- if (hasParameter('unpairall')) {
1630
- this.log.info('***Commissioning controller unpairing all nodes...');
1631
- const nodeIds = this.commissioningController.getCommissionedNodes();
1632
- for (const nodeId of nodeIds) {
1633
- this.log.info('***Commissioning controller unpairing node:', nodeId);
1634
- await this.commissioningController.removeNode(nodeId);
1635
- }
1636
- return;
1637
- }
1638
-
1639
- if (hasParameter('discover')) {
1640
- // const discover = await this.commissioningController.discoverCommissionableDevices({ productId: 0x8000, deviceType: 0xfff1 });
1641
- // console.log(discover);
1642
- }
1643
-
1644
- if (!this.commissioningController.isCommissioned()) {
1645
- this.log.info('***Commissioning controller is not commissioned: use matterbridge -controller -pairingcode [pairingcode] to commission a device');
1646
- return;
1647
- }
1648
-
1649
- const nodeIds = this.commissioningController.getCommissionedNodes();
1650
- this.log.info(`***Commissioning controller is commissioned ${this.commissioningController.isCommissioned()} and has ${nodeIds.length} nodes commisioned: `);
1651
- for (const nodeId of nodeIds) {
1652
- this.log.info(`***Connecting to commissioned node: ${nodeId}`);
1653
-
1654
- const node = await this.commissioningController.connectNode(nodeId, {
1655
- autoSubscribe: false,
1656
- attributeChangedCallback: (peerNodeId, { path: { nodeId, clusterId, endpointId, attributeName }, value }) =>
1657
- this.log.info(`***Commissioning controller attributeChangedCallback ${peerNodeId}: attribute ${nodeId}/${endpointId}/${clusterId}/${attributeName} changed to ${Logger.toJSON(value)}`),
1658
- eventTriggeredCallback: (peerNodeId, { path: { nodeId, clusterId, endpointId, eventName }, events }) =>
1659
- this.log.info(`***Commissioning controller eventTriggeredCallback ${peerNodeId}: Event ${nodeId}/${endpointId}/${clusterId}/${eventName} triggered with ${Logger.toJSON(events)}`),
1660
- stateInformationCallback: (peerNodeId, info) => {
1661
- switch (info) {
1662
- case NodeStateInformation.Connected:
1663
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} connected`);
1664
- break;
1665
- case NodeStateInformation.Disconnected:
1666
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} disconnected`);
1667
- break;
1668
- case NodeStateInformation.Reconnecting:
1669
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} reconnecting`);
1670
- break;
1671
- case NodeStateInformation.WaitingForDeviceDiscovery:
1672
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} waiting for device discovery`);
1673
- break;
1674
- case NodeStateInformation.StructureChanged:
1675
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} structure changed`);
1676
- break;
1677
- case NodeStateInformation.Decommissioned:
1678
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} decommissioned`);
1679
- break;
1680
- default:
1681
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} NodeStateInformation.${info}`);
1682
- break;
1683
- }
1684
- },
1685
- });
1686
-
1687
- node.logStructure();
1688
-
1689
- // Get the interaction client
1690
- this.log.info('Getting the interaction client');
1691
- const interactionClient = await node.getInteractionClient();
1692
- let cluster;
1693
- let attributes;
1694
-
1695
- // Log BasicInformationCluster
1696
- cluster = BasicInformationCluster;
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 PowerSourceCluster
1708
- cluster = PowerSourceCluster;
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 ThreadNetworkDiagnostics
1720
- cluster = ThreadNetworkDiagnosticsCluster;
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
- // Log SwitchCluster
1732
- cluster = SwitchCluster;
1733
- attributes = await interactionClient.getMultipleAttributes({
1734
- attributes: [{ clusterId: cluster.id }],
1735
- });
1736
- if (attributes.length > 0) this.log.info(`Cluster: ${idn}${cluster.name}${rs}${nf} attributes:`);
1737
- attributes.forEach((attribute) => {
1738
- this.log.info(
1739
- `- 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}`,
1740
- );
1741
- });
1742
-
1743
- this.log.info('Subscribing to all attributes and events');
1744
- await node.subscribeAllAttributesAndEvents({
1745
- ignoreInitialTriggers: false,
1746
- attributeChangedCallback: ({ path: { nodeId, clusterId, endpointId, attributeName }, version, value }) =>
1747
- this.log.info(
1748
- `***${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}`,
1749
- ),
1750
- eventTriggeredCallback: ({ path: { nodeId, clusterId, endpointId, eventName }, events }) => {
1751
- this.log.info(
1752
- `***${db}Commissioning controller eventTriggeredCallback: event ${BLUE}${nodeId}${db}/${or}${endpointId}${db}/${hk}${getClusterNameById(clusterId)}${db}/${zb}${eventName}${db} triggered with ${debugStringify(events ?? { none: true })}`,
1753
- );
1754
- },
1755
- });
1756
- this.log.info('Subscribed to all attributes and events');
1757
- }
1758
- */
1759
1260
  }
1760
- /** ***********************************************************************************************************************************/
1761
- /** Matter.js methods */
1762
- /** ***********************************************************************************************************************************/
1763
- /**
1764
- * Starts the matter storage process with name Matterbridge.
1765
- * @returns {Promise<void>} - A promise that resolves when the storage process is started.
1766
- */
1767
1261
  async startMatterStorage() {
1768
- // Setup Matter storage
1769
1262
  this.log.info(`Starting matter node storage...`);
1770
1263
  this.matterStorageService = this.environment.get(StorageService);
1771
1264
  this.log.info(`Matter node storage service created: ${this.matterStorageService.location}`);
@@ -1773,25 +1266,13 @@ export class Matterbridge extends EventEmitter {
1773
1266
  this.log.info('Matter node storage manager "Matterbridge" created');
1774
1267
  this.matterbridgeContext = await this.createServerNodeContext('Matterbridge', 'Matterbridge', bridge.code, this.aggregatorVendorId, 'Matterbridge', this.aggregatorProductId, 'Matterbridge aggregator');
1775
1268
  this.log.info('Matter node storage started');
1776
- // Backup matter storage since it is created/opened correctly
1777
1269
  await this.backupMatterStorage(path.join(this.matterbridgeDirectory, this.matterStorageName), path.join(this.matterbridgeDirectory, this.matterStorageName + '.backup'));
1778
1270
  }
1779
- /**
1780
- * Makes a backup copy of the specified matter storage directory.
1781
- *
1782
- * @param storageName - The name of the storage directory to be backed up.
1783
- * @param backupName - The name of the backup directory to be created.
1784
- * @returns {Promise<void>} A promise that resolves when the has been done.
1785
- */
1786
1271
  async backupMatterStorage(storageName, backupName) {
1787
1272
  this.log.info('Creating matter node storage backup...');
1788
1273
  await copyDirectory(storageName, backupName);
1789
1274
  this.log.info('Created matter node storage backup');
1790
1275
  }
1791
- /**
1792
- * Stops the matter storage.
1793
- * @returns {Promise<void>} A promise that resolves when the storage is stopped.
1794
- */
1795
1276
  async stopMatterStorage() {
1796
1277
  this.log.info('Closing matter node storage...');
1797
1278
  this.matterStorageManager?.close();
@@ -1800,19 +1281,6 @@ export class Matterbridge extends EventEmitter {
1800
1281
  this.matterbridgeContext = undefined;
1801
1282
  this.log.info('Matter node storage closed');
1802
1283
  }
1803
- /**
1804
- * Creates a server node storage context.
1805
- *
1806
- * @param {string} pluginName - The name of the plugin.
1807
- * @param {string} deviceName - The name of the device.
1808
- * @param {DeviceTypeId} deviceType - The device type of the device.
1809
- * @param {number} vendorId - The vendor ID.
1810
- * @param {string} vendorName - The vendor name.
1811
- * @param {number} productId - The product ID.
1812
- * @param {string} productName - The product name.
1813
- * @param {string} [serialNumber] - The serial number of the device (optional).
1814
- * @returns {Promise<StorageContext>} The storage context for the commissioning server.
1815
- */
1816
1284
  async createServerNodeContext(pluginName, deviceName, deviceType, vendorId, vendorName, productId, productName, serialNumber) {
1817
1285
  const { randomBytes } = await import('node:crypto');
1818
1286
  if (!this.matterStorageService)
@@ -1846,15 +1314,6 @@ export class Matterbridge extends EventEmitter {
1846
1314
  this.log.debug(`- hardwareVersion: ${await storageContext.get('hardwareVersion')} hardwareVersionString: ${await storageContext.get('hardwareVersionString')}`);
1847
1315
  return storageContext;
1848
1316
  }
1849
- /**
1850
- * Creates a server node.
1851
- *
1852
- * @param {StorageContext} storageContext - The storage context for the server node.
1853
- * @param {number} [port=5540] - The port number for the server node. Defaults to 5540.
1854
- * @param {number} [passcode=20242025] - The passcode for the server node. Defaults to 20242025.
1855
- * @param {number} [discriminator=3850] - The discriminator for the server node. Defaults to 3850.
1856
- * @returns {Promise<ServerNode<ServerNode.RootEndpoint>>} A promise that resolves to the created server node.
1857
- */
1858
1317
  async createServerNode(storageContext, port = 5540, passcode = 20242025, discriminator = 3850) {
1859
1318
  const storeId = await storageContext.get('storeId');
1860
1319
  this.log.notice(`Creating server node for ${storeId} on port ${port} with passcode ${passcode} and discriminator ${discriminator}...`);
@@ -1864,33 +1323,21 @@ export class Matterbridge extends EventEmitter {
1864
1323
  this.log.debug(`- uniqueId: ${await storageContext.get('uniqueId')}`);
1865
1324
  this.log.debug(`- softwareVersion: ${await storageContext.get('softwareVersion')} softwareVersionString: ${await storageContext.get('softwareVersionString')}`);
1866
1325
  this.log.debug(`- hardwareVersion: ${await storageContext.get('hardwareVersion')} hardwareVersionString: ${await storageContext.get('hardwareVersionString')}`);
1867
- /**
1868
- * Create a Matter ServerNode, which contains the Root Endpoint and all relevant data and configuration
1869
- */
1870
1326
  const serverNode = await ServerNode.create({
1871
- // Required: Give the Node a unique ID which is used to store the state of this node
1872
1327
  id: storeId,
1873
- // Provide Network relevant configuration like the port
1874
- // Optional when operating only one device on a host, Default port is 5540
1875
1328
  network: {
1876
1329
  listeningAddressIpv4: this.ipv4address,
1877
1330
  listeningAddressIpv6: this.ipv6address,
1878
1331
  port,
1879
1332
  },
1880
- // Provide Commissioning relevant settings
1881
- // Optional for development/testing purposes
1882
1333
  commissioning: {
1883
1334
  passcode,
1884
1335
  discriminator,
1885
1336
  },
1886
- // Provide Node announcement settings
1887
- // Optional: If Ommitted some development defaults are used
1888
1337
  productDescription: {
1889
1338
  name: await storageContext.get('deviceName'),
1890
1339
  deviceType: DeviceTypeId(await storageContext.get('deviceType')),
1891
1340
  },
1892
- // Provide defaults for the BasicInformation cluster on the Root endpoint
1893
- // Optional: If Omitted some development defaults are used
1894
1341
  basicInformation: {
1895
1342
  vendorId: VendorId(await storageContext.get('vendorId')),
1896
1343
  vendorName: await storageContext.get('vendorName'),
@@ -1907,13 +1354,12 @@ export class Matterbridge extends EventEmitter {
1907
1354
  },
1908
1355
  });
1909
1356
  const sanitizeFabrics = (fabrics, resetSessions = false) => {
1910
- // New type of fabric information: Record<FabricIndex, ExposedFabricInformation>
1911
1357
  const sanitizedFabrics = this.sanitizeFabricInformations(Array.from(Object.values(fabrics)));
1912
1358
  this.log.info(`Fabrics: ${debugStringify(sanitizedFabrics)}`);
1913
1359
  if (this.bridgeMode === 'bridge') {
1914
1360
  this.matterbridgeFabricInformations = sanitizedFabrics;
1915
1361
  if (resetSessions)
1916
- this.matterbridgeSessionInformations = undefined; // Changed cause Invoke Matterbridge.operationalCredentials.updateFabricLabel is sent after the session is created
1362
+ this.matterbridgeSessionInformations = undefined;
1917
1363
  this.matterbridgePaired = true;
1918
1364
  }
1919
1365
  if (this.bridgeMode === 'childbridge') {
@@ -1921,19 +1367,13 @@ export class Matterbridge extends EventEmitter {
1921
1367
  if (plugin) {
1922
1368
  plugin.fabricInformations = sanitizedFabrics;
1923
1369
  if (resetSessions)
1924
- plugin.sessionInformations = undefined; // Changed cause Invoke Matterbridge.operationalCredentials.updateFabricLabel is sent after the session is created
1370
+ plugin.sessionInformations = undefined;
1925
1371
  plugin.paired = true;
1926
1372
  }
1927
1373
  }
1928
1374
  };
1929
- /**
1930
- * This event is triggered when the device is initially commissioned successfully.
1931
- * This means: It is added to the first fabric.
1932
- */
1933
1375
  serverNode.lifecycle.commissioned.on(() => this.log.notice(`Server node for ${storeId} was initially commissioned successfully!`));
1934
- /** This event is triggered when all fabrics are removed from the device, usually it also does a factory reset then. */
1935
1376
  serverNode.lifecycle.decommissioned.on(() => this.log.notice(`Server node for ${storeId} was fully decommissioned successfully!`));
1936
- /** This event is triggered when the device went online. This means that it is discoverable in the network. */
1937
1377
  serverNode.lifecycle.online.on(async () => {
1938
1378
  this.log.notice(`Server node for ${storeId} is online`);
1939
1379
  if (!serverNode.lifecycle.isCommissioned) {
@@ -1980,7 +1420,6 @@ export class Matterbridge extends EventEmitter {
1980
1420
  this.frontend.wssSendRefreshRequired();
1981
1421
  this.frontend.wssSendSnackbarMessage(`${storeId} is online`);
1982
1422
  });
1983
- /** This event is triggered when the device went offline. it is not longer discoverable or connectable in the network. */
1984
1423
  serverNode.lifecycle.offline.on(() => {
1985
1424
  this.log.notice(`Server node for ${storeId} is offline`);
1986
1425
  if (this.bridgeMode === 'bridge') {
@@ -2002,10 +1441,6 @@ export class Matterbridge extends EventEmitter {
2002
1441
  }
2003
1442
  this.frontend.wssSendRefreshRequired();
2004
1443
  });
2005
- /**
2006
- * This event is triggered when a fabric is added, removed or updated on the device. Use this if more granular
2007
- * information is needed.
2008
- */
2009
1444
  serverNode.events.commissioning.fabricsChanged.on((fabricIndex, fabricAction) => {
2010
1445
  let action = '';
2011
1446
  switch (fabricAction) {
@@ -2039,24 +1474,16 @@ export class Matterbridge extends EventEmitter {
2039
1474
  }
2040
1475
  }
2041
1476
  };
2042
- /**
2043
- * This event is triggered when an operative new session was opened by a Controller.
2044
- * It is not triggered for the initial commissioning process, just afterwards for real connections.
2045
- */
2046
1477
  serverNode.events.sessions.opened.on((session) => {
2047
1478
  this.log.notice(`Session opened on server node for ${storeId}: ${debugStringify(session)}`);
2048
1479
  sanitizeSessions(Object.values(serverNode.state.sessions.sessions));
2049
1480
  this.frontend.wssSendRefreshRequired();
2050
1481
  });
2051
- /**
2052
- * This event is triggered when an operative session is closed by a Controller or because the Device goes offline.
2053
- */
2054
1482
  serverNode.events.sessions.closed.on((session) => {
2055
1483
  this.log.notice(`Session closed on server node for ${storeId}: ${debugStringify(session)}`);
2056
1484
  sanitizeSessions(Object.values(serverNode.state.sessions.sessions));
2057
1485
  this.frontend.wssSendRefreshRequired();
2058
1486
  });
2059
- /** This event is triggered when a subscription gets added or removed on an operative session. */
2060
1487
  serverNode.events.sessions.subscriptionsChanged.on((session) => {
2061
1488
  this.log.notice(`Session subscriptions changed on server node for ${storeId}: ${debugStringify(session)}`);
2062
1489
  sanitizeSessions(Object.values(serverNode.state.sessions.sessions));
@@ -2065,42 +1492,24 @@ export class Matterbridge extends EventEmitter {
2065
1492
  this.log.info(`Created server node for ${storeId}`);
2066
1493
  return serverNode;
2067
1494
  }
2068
- /**
2069
- * Starts the specified server node.
2070
- *
2071
- * @param {ServerNode} [matterServerNode] - The server node to start.
2072
- * @returns {Promise<void>} A promise that resolves when the server node has started.
2073
- */
2074
1495
  async startServerNode(matterServerNode) {
2075
1496
  if (!matterServerNode)
2076
1497
  return;
2077
1498
  this.log.notice(`Starting ${matterServerNode.id} server node`);
2078
1499
  await matterServerNode.start();
2079
1500
  }
2080
- /**
2081
- * Stops the specified server node.
2082
- *
2083
- * @param {ServerNode} matterServerNode - The server node to stop.
2084
- * @returns {Promise<void>} A promise that resolves when the server node has stopped.
2085
- */
2086
1501
  async stopServerNode(matterServerNode) {
2087
1502
  if (!matterServerNode)
2088
1503
  return;
2089
1504
  this.log.notice(`Closing ${matterServerNode.id} server node`);
2090
1505
  try {
2091
- await withTimeout(matterServerNode.close(), 30000); // 30 seconds timeout to allow slow devices to close gracefully
1506
+ await withTimeout(matterServerNode.close(), 30000);
2092
1507
  this.log.info(`Closed ${matterServerNode.id} server node`);
2093
1508
  }
2094
1509
  catch (error) {
2095
1510
  this.log.error(`Failed to close ${matterServerNode.id} server node: ${error instanceof Error ? error.message : error}`);
2096
1511
  }
2097
1512
  }
2098
- /**
2099
- * Advertises the specified server node.
2100
- *
2101
- * @param {ServerNode} [matterServerNode] - The server node to advertise.
2102
- * @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.
2103
- */
2104
1513
  async advertiseServerNode(matterServerNode) {
2105
1514
  if (matterServerNode) {
2106
1515
  await matterServerNode.env.get(DeviceCommissioner)?.allowBasicCommissioning();
@@ -2109,44 +1518,23 @@ export class Matterbridge extends EventEmitter {
2109
1518
  return { qrPairingCode, manualPairingCode };
2110
1519
  }
2111
1520
  }
2112
- /**
2113
- * Stop advertise the specified server node.
2114
- *
2115
- * @param {ServerNode} [matterServerNode] - The server node to advertise.
2116
- * @returns {Promise<void>} A promise that resolves when the server node has stopped advertising.
2117
- */
2118
1521
  async stopAdvertiseServerNode(matterServerNode) {
2119
1522
  if (matterServerNode && matterServerNode.lifecycle.isOnline) {
2120
1523
  await matterServerNode.env.get(DeviceCommissioner)?.endCommissioning();
2121
1524
  this.log.notice(`Stopped advertising for ${matterServerNode.id}`);
2122
1525
  }
2123
1526
  }
2124
- /**
2125
- * Creates an aggregator node with the specified storage context.
2126
- *
2127
- * @param {StorageContext} storageContext - The storage context for the aggregator node.
2128
- * @returns {Promise<EndpointNode<AggregatorEndpoint>>} A promise that resolves to the created aggregator node.
2129
- */
2130
1527
  async createAggregatorNode(storageContext) {
2131
1528
  this.log.notice(`Creating ${await storageContext.get('storeId')} aggregator `);
2132
1529
  const aggregatorNode = new EndpointNode(AggregatorEndpoint, { id: `${await storageContext.get('storeId')}` });
2133
1530
  return aggregatorNode;
2134
1531
  }
2135
- /**
2136
- * Adds a MatterbridgeEndpoint to the specified plugin.
2137
- *
2138
- * @param {string} pluginName - The name of the plugin.
2139
- * @param {MatterbridgeEndpoint} device - The device to add as a bridged endpoint.
2140
- * @returns {Promise<void>} A promise that resolves when the bridged endpoint has been added.
2141
- */
2142
1532
  async addBridgedEndpoint(pluginName, device) {
2143
- // Check if the plugin is registered
2144
1533
  const plugin = this.plugins.get(pluginName);
2145
1534
  if (!plugin) {
2146
1535
  this.log.error(`Error adding bridged endpoint ${dev}${device.deviceName}${er} (${zb}${device.id}${er}) plugin ${plg}${pluginName}${er} not found`);
2147
1536
  return;
2148
1537
  }
2149
- // Register and add the device to the matterbridge aggregator node
2150
1538
  if (this.bridgeMode === 'bridge') {
2151
1539
  this.log.debug(`Adding bridged endpoint ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} to Matterbridge aggregator node`);
2152
1540
  if (!this.aggregatorNode)
@@ -2169,26 +1557,16 @@ export class Matterbridge extends EventEmitter {
2169
1557
  plugin.registeredDevices++;
2170
1558
  if (plugin.addedDevices !== undefined)
2171
1559
  plugin.addedDevices++;
2172
- // Add the device to the DeviceManager
2173
1560
  this.devices.set(device);
2174
1561
  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}`);
2175
1562
  }
2176
- /**
2177
- * Removes a MatterbridgeEndpoint from the specified plugin.
2178
- *
2179
- * @param {string} pluginName - The name of the plugin.
2180
- * @param {MatterbridgeEndpoint} device - The device to remove as a bridged endpoint.
2181
- * @returns {Promise<void>} A promise that resolves when the bridged endpoint has been removed.
2182
- */
2183
1563
  async removeBridgedEndpoint(pluginName, device) {
2184
1564
  this.log.debug(`Removing bridged endpoint ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} (${zb}${device.name}${db}) for plugin ${plg}${pluginName}${db}`);
2185
- // Check if the plugin is registered
2186
1565
  const plugin = this.plugins.get(pluginName);
2187
1566
  if (!plugin) {
2188
1567
  this.log.error(`Error removing bridged endpoint ${dev}${device.deviceName}${er} (${zb}${device.name}${er}) for plugin ${plg}${pluginName}${er}: plugin not found`);
2189
1568
  return;
2190
1569
  }
2191
- // Register and add the device to the matterbridge aggregator node
2192
1570
  if (this.bridgeMode === 'bridge') {
2193
1571
  if (!this.aggregatorNode) {
2194
1572
  this.log.error(`Error removing bridged endpoint ${dev}${device.deviceName}${er} (${zb}${device.name}${er}) for plugin ${plg}${pluginName}${er}: aggregator node not found`);
@@ -2203,7 +1581,6 @@ export class Matterbridge extends EventEmitter {
2203
1581
  }
2204
1582
  else if (this.bridgeMode === 'childbridge') {
2205
1583
  if (plugin.type === 'AccessoryPlatform') {
2206
- // Nothing to do here since the server node has no aggregator node but only the device itself
2207
1584
  }
2208
1585
  else if (plugin.type === 'DynamicPlatform') {
2209
1586
  if (!plugin.aggregatorNode) {
@@ -2218,27 +1595,16 @@ export class Matterbridge extends EventEmitter {
2218
1595
  if (plugin.addedDevices !== undefined)
2219
1596
  plugin.addedDevices--;
2220
1597
  }
2221
- // Remove the device from the DeviceManager
2222
1598
  this.devices.remove(device);
2223
1599
  }
2224
- /**
2225
- * Removes all bridged endpoints from the specified plugin.
2226
- *
2227
- * @param {string} pluginName - The name of the plugin.
2228
- * @returns {Promise<void>} A promise that resolves when all bridged endpoints have been removed.
2229
- */
2230
- async removeAllBridgedEndpoints(pluginName) {
1600
+ async removeAllBridgedEndpoints(pluginName, delay = 0) {
2231
1601
  this.log.debug(`Removing all bridged endpoints for plugin ${plg}${pluginName}${db}`);
2232
1602
  for (const device of this.devices.array().filter((device) => device.plugin === pluginName)) {
2233
1603
  await this.removeBridgedEndpoint(pluginName, device);
1604
+ if (delay > 0)
1605
+ await new Promise((resolve) => setTimeout(resolve, delay));
2234
1606
  }
2235
1607
  }
2236
- /**
2237
- * Sanitizes the fabric information by converting bigint properties to strings because `res.json` doesn't support bigint.
2238
- *
2239
- * @param {ExposedFabricInformation[]} fabricInfo - The array of exposed fabric information objects.
2240
- * @returns {SanitizedExposedFabricInformation[]} An array of sanitized exposed fabric information objects.
2241
- */
2242
1608
  sanitizeFabricInformations(fabricInfo) {
2243
1609
  return fabricInfo.map((info) => {
2244
1610
  return {
@@ -2252,12 +1618,6 @@ export class Matterbridge extends EventEmitter {
2252
1618
  };
2253
1619
  });
2254
1620
  }
2255
- /**
2256
- * Sanitizes the session information by converting bigint properties to strings because `res.json` doesn't support bigint.
2257
- *
2258
- * @param {SessionInformation[]} sessionInfo - The array of session information objects.
2259
- * @returns {SanitizedSessionInformation[]} An array of sanitized session information objects.
2260
- */
2261
1621
  sanitizeSessionInformation(sessionInfo) {
2262
1622
  return sessionInfo
2263
1623
  .filter((session) => session.isPeerActive)
@@ -2285,11 +1645,6 @@ export class Matterbridge extends EventEmitter {
2285
1645
  };
2286
1646
  });
2287
1647
  }
2288
- /**
2289
- * Sets the reachability of the specified aggregator node bridged devices and trigger.
2290
- * @param {EndpointNode<AggregatorEndpoint>} aggregatorNode - The aggregator node to set the reachability for.
2291
- * @param {boolean} reachable - A boolean indicating the reachability status to set.
2292
- */
2293
1648
  async setAggregatorReachability(aggregatorNode, reachable) {
2294
1649
  for (const child of aggregatorNode.parts) {
2295
1650
  this.log.debug(`Setting reachability of ${child?.deviceName} to ${reachable}`);
@@ -2335,37 +1690,14 @@ export class Matterbridge extends EventEmitter {
2335
1690
  }
2336
1691
  return vendorName;
2337
1692
  };
2338
- /**
2339
- * Spawns a child process with the given command and arguments.
2340
- * @param {string} command - The command to execute.
2341
- * @param {string[]} args - The arguments to pass to the command (default: []).
2342
- * @returns {Promise<boolean>} A promise that resolves when the child process exits successfully, or rejects if there is an error.
2343
- */
2344
1693
  async spawnCommand(command, args = []) {
2345
1694
  const { spawn } = await import('node:child_process');
2346
- /*
2347
- npm > npm.cmd on windows
2348
- cmd.exe ['dir'] on windows
2349
- await this.spawnCommand('npm', ['install', '-g', 'matterbridge']);
2350
- process.on('unhandledRejection', (reason, promise) => {
2351
- this.log.error('Unhandled Rejection at:', promise, 'reason:', reason);
2352
- });
2353
-
2354
- spawn - [14:27:21.125] [Matterbridge:spawn]: changed 38 packages in 4s
2355
- spawn - [14:27:21.125] [Matterbridge:spawn]: 10 packages are looking for funding run `npm fund` for details
2356
- debug - [14:27:21.131] [Matterbridge]: Child process exited with code 0 and signal null
2357
- debug - [14:27:21.131] [Matterbridge]: Child process stdio streams have closed with code 0
2358
- */
2359
1695
  const cmdLine = command + ' ' + args.join(' ');
2360
1696
  if (process.platform === 'win32' && command === 'npm') {
2361
- // Must be spawn('cmd.exe', ['/c', 'npm -g install <package>']);
2362
1697
  const argstring = 'npm ' + args.join(' ');
2363
1698
  args.splice(0, args.length, '/c', argstring);
2364
1699
  command = 'cmd.exe';
2365
1700
  }
2366
- // Decide when using sudo on linux
2367
- // When you need sudo: Spawn stderr: npm error Error: EACCES: permission denied
2368
- // When you don't need sudo: Failed to start child process "npm install -g matterbridge-eve-door": spawn sudo ENOENT
2369
1701
  if (hasParameter('sudo') || (process.platform === 'linux' && command === 'npm' && !hasParameter('docker') && !hasParameter('nosudo'))) {
2370
1702
  args.unshift(command);
2371
1703
  command = 'sudo';
@@ -2424,4 +1756,3 @@ export class Matterbridge extends EventEmitter {
2424
1756
  });
2425
1757
  }
2426
1758
  }
2427
- //# sourceMappingURL=matterbridge.js.map