matterbridge 2.1.5 → 2.1.6-dev.1

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