matterbridge 1.6.7 → 1.6.8-dev.10

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 (97) hide show
  1. package/CHANGELOG.md +23 -3
  2. package/README-SERVICE.md +12 -3
  3. package/README.md +3 -1
  4. package/dist/cli.js +0 -26
  5. package/dist/cluster/export.js +0 -2
  6. package/dist/defaultConfigSchema.js +3 -24
  7. package/dist/deviceManager.js +1 -26
  8. package/dist/index.js +0 -30
  9. package/dist/logger/export.js +0 -1
  10. package/dist/matter/export.js +5 -1
  11. package/dist/matterbridge.js +239 -661
  12. package/dist/matterbridgeAccessoryPlatform.js +0 -33
  13. package/dist/matterbridgeBehaviors.js +1 -29
  14. package/dist/matterbridgeDevice.js +24 -986
  15. package/dist/matterbridgeDeviceTypes.js +11 -82
  16. package/dist/matterbridgeDynamicPlatform.js +0 -33
  17. package/dist/matterbridgeEdge.js +3 -534
  18. package/dist/matterbridgeEndpoint.js +26 -1111
  19. package/dist/matterbridgePlatform.js +65 -95
  20. package/dist/matterbridgeTypes.js +0 -24
  21. package/dist/matterbridgeWebsocket.js +0 -45
  22. package/dist/pluginManager.js +3 -238
  23. package/dist/storage/export.js +0 -1
  24. package/dist/utils/colorUtils.js +2 -205
  25. package/dist/utils/export.js +0 -1
  26. package/dist/utils/utils.js +7 -252
  27. package/npm-shrinkwrap.json +17 -81
  28. package/package.json +1 -2
  29. package/dist/cli.d.ts +0 -25
  30. package/dist/cli.d.ts.map +0 -1
  31. package/dist/cli.js.map +0 -1
  32. package/dist/cluster/export.d.ts +0 -2
  33. package/dist/cluster/export.d.ts.map +0 -1
  34. package/dist/cluster/export.js.map +0 -1
  35. package/dist/defaultConfigSchema.d.ts +0 -27
  36. package/dist/defaultConfigSchema.d.ts.map +0 -1
  37. package/dist/defaultConfigSchema.js.map +0 -1
  38. package/dist/deviceManager.d.ts +0 -46
  39. package/dist/deviceManager.d.ts.map +0 -1
  40. package/dist/deviceManager.js.map +0 -1
  41. package/dist/index.d.ts +0 -40
  42. package/dist/index.d.ts.map +0 -1
  43. package/dist/index.js.map +0 -1
  44. package/dist/logger/export.d.ts +0 -2
  45. package/dist/logger/export.d.ts.map +0 -1
  46. package/dist/logger/export.js.map +0 -1
  47. package/dist/matter/export.d.ts +0 -6
  48. package/dist/matter/export.d.ts.map +0 -1
  49. package/dist/matter/export.js.map +0 -1
  50. package/dist/matterbridge.d.ts +0 -466
  51. package/dist/matterbridge.d.ts.map +0 -1
  52. package/dist/matterbridge.js.map +0 -1
  53. package/dist/matterbridgeAccessoryPlatform.d.ts +0 -39
  54. package/dist/matterbridgeAccessoryPlatform.d.ts.map +0 -1
  55. package/dist/matterbridgeAccessoryPlatform.js.map +0 -1
  56. package/dist/matterbridgeBehaviors.d.ts +0 -942
  57. package/dist/matterbridgeBehaviors.d.ts.map +0 -1
  58. package/dist/matterbridgeBehaviors.js.map +0 -1
  59. package/dist/matterbridgeDevice.d.ts +0 -7063
  60. package/dist/matterbridgeDevice.d.ts.map +0 -1
  61. package/dist/matterbridgeDevice.js.map +0 -1
  62. package/dist/matterbridgeDeviceTypes.d.ts +0 -109
  63. package/dist/matterbridgeDeviceTypes.d.ts.map +0 -1
  64. package/dist/matterbridgeDeviceTypes.js.map +0 -1
  65. package/dist/matterbridgeDynamicPlatform.d.ts +0 -39
  66. package/dist/matterbridgeDynamicPlatform.d.ts.map +0 -1
  67. package/dist/matterbridgeDynamicPlatform.js.map +0 -1
  68. package/dist/matterbridgeEdge.d.ts +0 -92
  69. package/dist/matterbridgeEdge.d.ts.map +0 -1
  70. package/dist/matterbridgeEdge.js.map +0 -1
  71. package/dist/matterbridgeEndpoint.d.ts +0 -10164
  72. package/dist/matterbridgeEndpoint.d.ts.map +0 -1
  73. package/dist/matterbridgeEndpoint.js.map +0 -1
  74. package/dist/matterbridgePlatform.d.ts +0 -114
  75. package/dist/matterbridgePlatform.d.ts.map +0 -1
  76. package/dist/matterbridgePlatform.js.map +0 -1
  77. package/dist/matterbridgeTypes.d.ts +0 -162
  78. package/dist/matterbridgeTypes.d.ts.map +0 -1
  79. package/dist/matterbridgeTypes.js.map +0 -1
  80. package/dist/matterbridgeWebsocket.d.ts +0 -49
  81. package/dist/matterbridgeWebsocket.d.ts.map +0 -1
  82. package/dist/matterbridgeWebsocket.js.map +0 -1
  83. package/dist/pluginManager.d.ts +0 -238
  84. package/dist/pluginManager.d.ts.map +0 -1
  85. package/dist/pluginManager.js.map +0 -1
  86. package/dist/storage/export.d.ts +0 -2
  87. package/dist/storage/export.d.ts.map +0 -1
  88. package/dist/storage/export.js.map +0 -1
  89. package/dist/utils/colorUtils.d.ts +0 -61
  90. package/dist/utils/colorUtils.d.ts.map +0 -1
  91. package/dist/utils/colorUtils.js.map +0 -1
  92. package/dist/utils/export.d.ts +0 -3
  93. package/dist/utils/export.d.ts.map +0 -1
  94. package/dist/utils/export.js.map +0 -1
  95. package/dist/utils/utils.d.ts +0 -221
  96. package/dist/utils/utils.d.ts.map +0 -1
  97. package/dist/utils/utils.js.map +0 -1
@@ -1,26 +1,3 @@
1
- /**
2
- * This file contains the class Matterbridge.
3
- *
4
- * @file matterbridge.ts
5
- * @author Luca Liguori
6
- * @date 2023-12-29
7
- * @version 1.5.2
8
- *
9
- * Copyright 2023, 2024, 2025 Luca Liguori.
10
- *
11
- * Licensed under the Apache License, Version 2.0 (the "License");
12
- * you may not use this file except in compliance with the License.
13
- * You may obtain a copy of the License at
14
- *
15
- * http://www.apache.org/licenses/LICENSE-2.0
16
- *
17
- * Unless required by applicable law or agreed to in writing, software
18
- * distributed under the License is distributed on an "AS IS" BASIS,
19
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20
- * See the License for the specific language governing permissions and
21
- * limitations under the License. *
22
- */
23
- // Node.js modules
24
1
  import { fileURLToPath } from 'url';
25
2
  import { promises as fs } from 'fs';
26
3
  import { exec, spawn } from 'child_process';
@@ -29,35 +6,27 @@ import EventEmitter from 'events';
29
6
  import os from 'os';
30
7
  import path from 'path';
31
8
  import { randomBytes } from 'crypto';
32
- // Package modules
33
9
  import https from 'https';
34
10
  import express from 'express';
35
11
  import WebSocket, { WebSocketServer } from 'ws';
36
- // NodeStorage and AnsiLogger modules
37
12
  import { NodeStorageManager } from 'node-persist-manager';
38
13
  import { AnsiLogger, UNDERLINE, UNDERLINEOFF, YELLOW, db, debugStringify, stringify, BRIGHT, RESET, er, nf, rs, wr, RED, GREEN, zb, CYAN, nt, idn, or, hk, BLUE } from 'node-ansi-logger';
39
- // Matterbridge
40
14
  import { MatterbridgeDevice } from './matterbridgeDevice.js';
41
15
  import { WS_ID_LOG, WS_ID_REFRESH_NEEDED, WS_ID_RESTART_NEEDED, wsMessageHandler } from './matterbridgeWebsocket.js';
42
16
  import { logInterfaces, wait, waiter, createZip, copyDirectory, getParameter, getIntParameter, hasParameter } from './utils/utils.js';
43
17
  import { PluginManager } from './pluginManager.js';
44
18
  import { DeviceManager } from './deviceManager.js';
45
19
  import { MatterbridgeEndpoint } from './matterbridgeEndpoint.js';
46
- // @matter
47
- import { DeviceTypeId, Logger, LogLevel as MatterLogLevel, LogFormat as MatterLogFormat, VendorId, StorageManager, EndpointServer } from '@matter/main';
20
+ import { DeviceTypeId, Logger, LogLevel as MatterLogLevel, LogFormat as MatterLogFormat, VendorId, StorageManager, EndpointServer, StorageService, Environment } from '@matter/main';
48
21
  import { BasicInformationCluster, BridgedDeviceBasicInformation, BridgedDeviceBasicInformationCluster, FixedLabelCluster, GeneralCommissioning, PowerSourceCluster, SwitchCluster, ThreadNetworkDiagnosticsCluster, UserLabelCluster, } from '@matter/main/clusters';
49
22
  import { getClusterNameById, ManualPairingCodeCodec, QrCodeSchema } from '@matter/main/types';
50
23
  import { StorageBackendDisk, StorageBackendJsonFile } from '@matter/nodejs';
51
- // @project-chip
52
24
  import { CommissioningController, CommissioningServer, MatterServer } from '@project-chip/matter.js';
53
25
  import { Aggregator, DeviceTypes, NodeStateInformation } from '@project-chip/matter.js/device';
54
- // Default colors
26
+ import { aggregator } from './matterbridgeDeviceTypes.js';
55
27
  const plg = '\u001B[38;5;33m';
56
28
  const dev = '\u001B[38;5;79m';
57
29
  const typ = '\u001B[38;5;207m';
58
- /**
59
- * Represents the Matterbridge application.
60
- */
61
30
  export class Matterbridge extends EventEmitter {
62
31
  systemInformation = {
63
32
  interfaceName: '',
@@ -94,7 +63,7 @@ export class Matterbridge extends EventEmitter {
94
63
  edge: hasParameter('edge'),
95
64
  readOnly: hasParameter('readonly'),
96
65
  profile: getParameter('profile'),
97
- loggerLevel: "info" /* LogLevel.INFO */,
66
+ loggerLevel: "info",
98
67
  fileLogger: false,
99
68
  matterLoggerLevel: MatterLogLevel.INFO,
100
69
  matterFileLogger: false,
@@ -133,7 +102,6 @@ export class Matterbridge extends EventEmitter {
133
102
  nodeContext;
134
103
  matterStorageName = 'matterbridge' + (getParameter('profile') ? '.' + getParameter('profile') : '') + '.json';
135
104
  nodeStorageName = 'storage' + (getParameter('profile') ? '.' + getParameter('profile') : '');
136
- // Cleanup
137
105
  hasCleanupStarted = false;
138
106
  initialized = false;
139
107
  execRunningCount = 0;
@@ -145,18 +113,16 @@ export class Matterbridge extends EventEmitter {
145
113
  sigtermHandler;
146
114
  exceptionHandler;
147
115
  rejectionHandler;
148
- // Frontend
149
116
  expressApp;
150
117
  httpServer;
151
118
  httpsServer;
152
119
  webSocketServer;
153
- // Matter
154
- mdnsInterface; // matter server mdnsInterface: e.g. 'eth0' or 'wlan0' or 'WiFi'
155
- ipv4address; // matter commissioning server listeningAddressIpv4
156
- ipv6address; // matter commissioning server listeningAddressIpv6
157
- port = 5540; // first commissioning server port
158
- passcode; // first commissioning server passcode
159
- discriminator; // first commissioning server discriminator
120
+ mdnsInterface;
121
+ ipv4address;
122
+ ipv6address;
123
+ port = 5540;
124
+ passcode;
125
+ discriminator;
160
126
  storageManager;
161
127
  matterbridgeContext;
162
128
  mattercontrollerContext;
@@ -167,26 +133,19 @@ export class Matterbridge extends EventEmitter {
167
133
  aggregatorVendorId = VendorId(getIntParameter('vendorId') ?? 0xfff1);
168
134
  aggregatorProductId = getIntParameter('productId') ?? 0x8000;
169
135
  static instance;
170
- // We load asyncronously so is private
171
136
  constructor() {
172
137
  super();
173
- // Bind the handler to the instance
174
138
  this.matterbridgeMessageHandler = wsMessageHandler.bind(this);
175
139
  }
140
+ getDevices() {
141
+ return this.devices.array();
142
+ }
143
+ getPlugins() {
144
+ return this.plugins.array();
145
+ }
176
146
  matterbridgeMessageHandler;
177
- /** ***********************************************************************************************************************************/
178
- /** loadInstance() and cleanup() methods */
179
- /** ***********************************************************************************************************************************/
180
- /**
181
- * Loads an instance of the Matterbridge class.
182
- * If an instance already exists, return that instance.
183
- *
184
- * @param initialize - Whether to initialize the Matterbridge instance after loading.
185
- * @returns The loaded Matterbridge instance.
186
- */
187
147
  static async loadInstance(initialize = false) {
188
148
  if (!Matterbridge.instance) {
189
- // eslint-disable-next-line no-console
190
149
  if (hasParameter('debug'))
191
150
  console.log(GREEN + 'Creating a new instance of Matterbridge.', initialize ? 'Initializing...' : 'Not initializing...', rs);
192
151
  Matterbridge.instance = new Matterbridge();
@@ -195,11 +154,6 @@ export class Matterbridge extends EventEmitter {
195
154
  }
196
155
  return Matterbridge.instance;
197
156
  }
198
- /**
199
- * Call cleanup().
200
- * @deprecated This method is deprecated and is only used for jest tests.
201
- *
202
- */
203
157
  async destroyInstance() {
204
158
  await this.cleanup('destroying instance...', false);
205
159
  await waiter('destroying instance...', () => {
@@ -207,60 +161,39 @@ export class Matterbridge extends EventEmitter {
207
161
  }, false, 60000, 100, false);
208
162
  await wait(1000, 'Wait for the global node_modules and matterbridge version', false);
209
163
  }
210
- /**
211
- * Initializes the Matterbridge application.
212
- *
213
- * @remarks
214
- * This method performs the necessary setup and initialization steps for the Matterbridge application.
215
- * It displays the help information if the 'help' parameter is provided, sets up the logger, checks the
216
- * node version, registers signal handlers, initializes storage, and parses the command line.
217
- *
218
- * @returns A Promise that resolves when the initialization is complete.
219
- */
220
164
  async initialize() {
221
- // Set the restart mode
222
165
  if (hasParameter('service'))
223
166
  this.restartMode = 'service';
224
167
  if (hasParameter('docker'))
225
168
  this.restartMode = 'docker';
226
- // Set the matterbridge directory
227
169
  this.homeDirectory = getParameter('homedir') ?? os.homedir();
228
170
  this.matterbridgeDirectory = path.join(this.homeDirectory, '.matterbridge');
229
- // Create matterbridge logger
230
- this.log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: hasParameter('debug') ? "debug" /* LogLevel.DEBUG */ : "info" /* LogLevel.INFO */ });
231
- // Initialize nodeStorage and nodeContext
171
+ this.log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4, logLevel: hasParameter('debug') ? "debug" : "info" });
232
172
  try {
233
173
  this.log.debug(`Creating node storage manager: ${CYAN}${this.nodeStorageName}${db}`);
234
174
  this.nodeStorage = new NodeStorageManager({ dir: path.join(this.matterbridgeDirectory, this.nodeStorageName), writeQueue: false, expiredInterval: undefined, logging: false });
235
175
  this.log.debug('Creating node storage context for matterbridge');
236
176
  this.nodeContext = await this.nodeStorage.createStorage('matterbridge');
237
- // TODO: Remove this code when node-persist-manager is updated
238
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
239
177
  const keys = (await this.nodeStorage?.storage.keys());
240
178
  for (const key of keys) {
241
179
  this.log.debug(`Checking node storage manager key: ${CYAN}${key}${db}`);
242
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
243
180
  await this.nodeStorage?.storage.get(key);
244
181
  }
245
182
  const storages = await this.nodeStorage.getStorageNames();
246
183
  for (const storage of storages) {
247
184
  this.log.debug(`Checking storage: ${CYAN}${storage}${db}`);
248
185
  const nodeContext = await this.nodeStorage?.createStorage(storage);
249
- // TODO: Remove this code when node-persist-manager is updated
250
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
251
186
  const keys = (await nodeContext?.storage.keys());
252
187
  keys.forEach(async (key) => {
253
188
  this.log.debug(`Checking key: ${CYAN}${storage}:${key}${db}`);
254
189
  await nodeContext?.get(key);
255
190
  });
256
191
  }
257
- // Creating a backup of the node storage since it is not corrupted
258
192
  this.log.debug('Creating node storage backup...');
259
193
  await copyDirectory(path.join(this.matterbridgeDirectory, this.nodeStorageName), path.join(this.matterbridgeDirectory, this.nodeStorageName + '.backup'));
260
194
  this.log.debug('Created node storage backup');
261
195
  }
262
196
  catch (error) {
263
- // Restoring the backup of the node storage since it is corrupted
264
197
  this.log.error(`Error creating node storage manager and context: ${error instanceof Error ? error.message : error}`);
265
198
  if (hasParameter('norestore')) {
266
199
  this.log.fatal(`The matterbridge node storage is corrupted. Parameter -norestore found: exiting...`);
@@ -275,51 +208,45 @@ export class Matterbridge extends EventEmitter {
275
208
  this.log.fatal('Fatal error creating node storage manager and context for matterbridge');
276
209
  throw new Error('Fatal error creating node storage manager and context for matterbridge');
277
210
  }
278
- // Set the first port to use for the commissioning server (will be incremented in childbridge mode)
279
211
  this.port = getIntParameter('port') ?? (await this.nodeContext.get('matterport', 5540)) ?? 5540;
280
- // Set the first passcode to use for the commissioning server (will be incremented in childbridge mode)
281
212
  this.passcode = this.passcode ?? getIntParameter('passcode') ?? (await this.nodeContext.get('matterpasscode'));
282
- // Set the first discriminator to use for the commissioning server (will be incremented in childbridge mode)
283
213
  this.discriminator = this.discriminator ?? getIntParameter('discriminator') ?? (await this.nodeContext.get('matterdiscriminator'));
284
214
  this.log.debug(`Initializing commissioning server for Matterbridge... on port ${this.port} with passcode ${this.passcode} and discriminator ${this.discriminator}`);
285
- // Set matterbridge logger level (context: matterbridgeLogLevel)
286
215
  if (hasParameter('logger')) {
287
216
  const level = getParameter('logger');
288
217
  if (level === 'debug') {
289
- this.log.logLevel = "debug" /* LogLevel.DEBUG */;
218
+ this.log.logLevel = "debug";
290
219
  }
291
220
  else if (level === 'info') {
292
- this.log.logLevel = "info" /* LogLevel.INFO */;
221
+ this.log.logLevel = "info";
293
222
  }
294
223
  else if (level === 'notice') {
295
- this.log.logLevel = "notice" /* LogLevel.NOTICE */;
224
+ this.log.logLevel = "notice";
296
225
  }
297
226
  else if (level === 'warn') {
298
- this.log.logLevel = "warn" /* LogLevel.WARN */;
227
+ this.log.logLevel = "warn";
299
228
  }
300
229
  else if (level === 'error') {
301
- this.log.logLevel = "error" /* LogLevel.ERROR */;
230
+ this.log.logLevel = "error";
302
231
  }
303
232
  else if (level === 'fatal') {
304
- this.log.logLevel = "fatal" /* LogLevel.FATAL */;
233
+ this.log.logLevel = "fatal";
305
234
  }
306
235
  else {
307
236
  this.log.warn(`Invalid matterbridge logger level: ${level}. Using default level "info".`);
308
- this.log.logLevel = "info" /* LogLevel.INFO */;
237
+ this.log.logLevel = "info";
309
238
  }
310
239
  }
311
240
  else {
312
- this.log.logLevel = await this.nodeContext.get('matterbridgeLogLevel', "info" /* LogLevel.INFO */);
241
+ this.log.logLevel = await this.nodeContext.get('matterbridgeLogLevel', "info");
313
242
  }
314
243
  MatterbridgeDevice.logLevel = this.log.logLevel;
315
- // Create the file logger for matterbridge (context: matterbridgeFileLog)
316
244
  if (hasParameter('filelogger') || (await this.nodeContext.get('matterbridgeFileLog', false))) {
317
245
  AnsiLogger.setGlobalLogfile(path.join(this.matterbridgeDirectory, this.matterbrideLoggerFile), this.log.logLevel, true);
318
246
  this.matterbridgeInformation.fileLogger = true;
319
247
  }
320
248
  this.log.notice('Matterbridge is starting...');
321
249
  this.log.debug(`Matterbridge logLevel: ${this.log.logLevel} fileLoger: ${this.matterbridgeInformation.fileLogger}.`);
322
- // Set matter.js logger level, format and logger (context: matterLogLevel)
323
250
  if (hasParameter('matterlogger')) {
324
251
  const level = getParameter('matterlogger');
325
252
  if (level === 'debug') {
@@ -350,7 +277,6 @@ export class Matterbridge extends EventEmitter {
350
277
  }
351
278
  Logger.format = MatterLogFormat.ANSI;
352
279
  Logger.setLogger('default', this.createMatterLogger());
353
- // Create the file logger for matter.js (context: matterFileLog)
354
280
  if (hasParameter('matterfilelogger') || (await this.nodeContext.get('matterFileLog', false))) {
355
281
  this.matterbridgeInformation.matterFileLogger = true;
356
282
  Logger.addLogger('matterfilelogger', await this.createMatterFileLogger(path.join(this.matterbridgeDirectory, this.matterLoggerFile), true), {
@@ -359,7 +285,6 @@ export class Matterbridge extends EventEmitter {
359
285
  });
360
286
  }
361
287
  this.log.debug(`Matter logLevel: ${Logger.defaultLogLevel} fileLoger: ${this.matterbridgeInformation.matterFileLogger}.`);
362
- // Set the interface to use for the matter server mdnsInterface
363
288
  if (hasParameter('mdnsinterface')) {
364
289
  this.mdnsInterface = getParameter('mdnsinterface');
365
290
  }
@@ -368,7 +293,6 @@ export class Matterbridge extends EventEmitter {
368
293
  if (this.mdnsInterface === '')
369
294
  this.mdnsInterface = undefined;
370
295
  }
371
- // Set the listeningAddressIpv4 for the matter commissioning server
372
296
  if (hasParameter('ipv4address')) {
373
297
  this.ipv4address = getParameter('ipv4address');
374
298
  }
@@ -377,7 +301,6 @@ export class Matterbridge extends EventEmitter {
377
301
  if (this.ipv4address === '')
378
302
  this.ipv4address = undefined;
379
303
  }
380
- // Set the listeningAddressIpv6 for the matter commissioning server
381
304
  if (hasParameter('ipv6address')) {
382
305
  this.ipv6address = getParameter('ipv6address');
383
306
  }
@@ -386,23 +309,17 @@ export class Matterbridge extends EventEmitter {
386
309
  if (this.ipv6address === '')
387
310
  this.ipv6address = undefined;
388
311
  }
389
- // Initialize PluginManager
390
312
  this.plugins = new PluginManager(this);
391
313
  await this.plugins.loadFromStorage();
392
- // Initialize DeviceManager
393
314
  this.devices = new DeviceManager(this, this.nodeContext);
394
- // Get the plugins from node storage and create the plugins node storage contexts
395
315
  for (const plugin of this.plugins) {
396
316
  const packageJson = await this.plugins.parse(plugin);
397
317
  if (packageJson === null && !hasParameter('add')) {
398
- // Try to reinstall the plugin from npm (for Docker pull and external plugins)
399
- // We don't do this when the add parameter is set because we shut down the process after adding the plugin
400
318
  this.log.info(`Error parsing plugin ${plg}${plugin.name}${nf}. Trying to reinstall it from npm.`);
401
319
  try {
402
320
  await this.spawnCommand('npm', ['install', '-g', plugin.name, '--omit=dev', '--verbose']);
403
321
  this.log.info(`Plugin ${plg}${plugin.name}${nf} reinstalled.`);
404
322
  plugin.error = false;
405
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
406
323
  }
407
324
  catch (error) {
408
325
  plugin.error = true;
@@ -419,7 +336,6 @@ export class Matterbridge extends EventEmitter {
419
336
  await plugin.nodeContext.set('description', plugin.description);
420
337
  await plugin.nodeContext.set('author', plugin.author);
421
338
  }
422
- // Log system info and create .matterbridge directory
423
339
  await this.logNodeAndSystemInfo();
424
340
  this.log.notice(`Matterbridge version ${this.matterbridgeVersion} ` +
425
341
  `${hasParameter('bridge') || (!hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'bridge') ? 'mode bridge ' : ''}` +
@@ -427,7 +343,6 @@ export class Matterbridge extends EventEmitter {
427
343
  `${hasParameter('controller') ? 'mode controller ' : ''}` +
428
344
  `${this.restartMode !== '' ? 'restart mode ' + this.restartMode + ' ' : ''}` +
429
345
  `running on ${this.systemInformation.osType} (v.${this.systemInformation.osRelease}) platform ${this.systemInformation.osPlatform} arch ${this.systemInformation.osArch}`);
430
- // Check node version and throw error
431
346
  const minNodeVersion = 18;
432
347
  const nodeVersion = process.versions.node;
433
348
  const versionMajor = parseInt(nodeVersion.split('.')[0]);
@@ -435,17 +350,10 @@ export class Matterbridge extends EventEmitter {
435
350
  this.log.error(`Node version ${versionMajor} is not supported. Please upgrade to ${minNodeVersion} or above.`);
436
351
  throw new Error(`Node version ${versionMajor} is not supported. Please upgrade to ${minNodeVersion} or above.`);
437
352
  }
438
- // Register process handlers
439
353
  this.registerProcessHandlers();
440
- // Parse command line
441
354
  await this.parseCommandLine();
442
355
  this.initialized = true;
443
356
  }
444
- /**
445
- * Parses the command line arguments and performs the corresponding actions.
446
- * @private
447
- * @returns {Promise<void>} A promise that resolves when the command line arguments have been processed, or the process exits.
448
- */
449
357
  async parseCommandLine() {
450
358
  if (hasParameter('help')) {
451
359
  this.log.info(`\nUsage: matterbridge [options]\n
@@ -553,14 +461,12 @@ export class Matterbridge extends EventEmitter {
553
461
  }
554
462
  if (hasParameter('factoryreset')) {
555
463
  try {
556
- // Delete matter storage file
557
464
  await fs.unlink(path.join(this.matterbridgeDirectory, this.matterStorageName));
558
465
  }
559
466
  catch (err) {
560
467
  this.log.error(`Error deleting storage: ${err}`);
561
468
  }
562
469
  try {
563
- // Delete node storage directory with its subdirectories
564
470
  await fs.rm(path.join(this.matterbridgeDirectory, this.nodeStorageName), { recursive: true });
565
471
  }
566
472
  catch (err) {
@@ -574,7 +480,6 @@ export class Matterbridge extends EventEmitter {
574
480
  this.emit('shutdown');
575
481
  return;
576
482
  }
577
- // Start the matter storage and create the matterbridge context
578
483
  try {
579
484
  await this.startMatterStorage('json', path.join(this.matterbridgeDirectory, this.matterStorageName));
580
485
  }
@@ -609,34 +514,28 @@ export class Matterbridge extends EventEmitter {
609
514
  this.emit('shutdown');
610
515
  return;
611
516
  }
612
- // Initialize frontend
613
517
  if (getIntParameter('frontend') !== 0 || getIntParameter('frontend') === undefined)
614
518
  await this.initializeFrontend(getIntParameter('frontend'));
615
- // Check each 60 minutes the latest versions
616
519
  this.checkUpdateInterval = setInterval(() => {
617
520
  this.getMatterbridgeLatestVersion();
618
521
  for (const plugin of this.plugins) {
619
522
  this.getPluginLatestVersion(plugin);
620
523
  }
621
524
  }, 60 * 60 * 1000);
622
- // Start the matterbridge in mode test
623
525
  if (hasParameter('test')) {
624
526
  this.bridgeMode = 'bridge';
625
527
  MatterbridgeDevice.bridgeMode = 'bridge';
626
528
  return;
627
529
  }
628
- // Start the matterbridge in mode controller
629
530
  if (hasParameter('controller')) {
630
531
  this.bridgeMode = 'controller';
631
532
  await this.startController();
632
533
  return;
633
534
  }
634
- // Check if the bridge mode is set and start matterbridge in bridge mode if not set
635
535
  if (!hasParameter('bridge') && !hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === '') {
636
536
  this.log.info('Setting default matterbridge start mode to bridge');
637
537
  await this.nodeContext?.set('bridgeMode', 'bridge');
638
538
  }
639
- // Start matterbridge in bridge mode
640
539
  if (hasParameter('bridge') || (!hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'bridge')) {
641
540
  this.bridgeMode = 'bridge';
642
541
  MatterbridgeDevice.bridgeMode = 'bridge';
@@ -645,7 +544,6 @@ export class Matterbridge extends EventEmitter {
645
544
  await this.startBridge();
646
545
  return;
647
546
  }
648
- // Start matterbridge in childbridge mode
649
547
  if (hasParameter('childbridge') || (!hasParameter('bridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'childbridge')) {
650
548
  this.bridgeMode = 'childbridge';
651
549
  MatterbridgeDevice.bridgeMode = 'childbridge';
@@ -655,28 +553,17 @@ export class Matterbridge extends EventEmitter {
655
553
  return;
656
554
  }
657
555
  }
658
- /**
659
- * Asynchronously loads and starts the registered plugins.
660
- *
661
- * This method is responsible for initializing and staarting all enabled plugins.
662
- * It ensures that each plugin is properly loaded and started before the ridge starts.
663
- *
664
- * @returns {Promise<void>} A promise that resolves when all plugins have been loaded and started.
665
- */
666
556
  async startPlugins() {
667
- // Check, load and start the plugins
668
557
  for (const plugin of this.plugins) {
669
558
  plugin.configJson = await this.plugins.loadConfig(plugin);
670
559
  plugin.schemaJson = await this.plugins.loadSchema(plugin);
671
- // Check if the plugin is available
672
560
  if (!(await this.plugins.resolve(plugin.path))) {
673
561
  this.log.error(`Plugin ${plg}${plugin.name}${er} not found or not validated. Disabling it.`);
674
562
  plugin.enabled = false;
675
563
  plugin.error = true;
676
564
  continue;
677
565
  }
678
- // Check if the plugin has a new version
679
- this.getPluginLatestVersion(plugin); // No await do it asyncronously
566
+ this.getPluginLatestVersion(plugin);
680
567
  if (!plugin.enabled) {
681
568
  this.log.info(`Plugin ${plg}${plugin.name}${nf} not enabled`);
682
569
  continue;
@@ -691,26 +578,20 @@ export class Matterbridge extends EventEmitter {
691
578
  plugin.addedDevices = undefined;
692
579
  plugin.qrPairingCode = undefined;
693
580
  plugin.manualPairingCode = undefined;
694
- this.plugins.load(plugin, true, 'Matterbridge is starting'); // No await do it asyncronously
581
+ this.plugins.load(plugin, true, 'Matterbridge is starting');
695
582
  }
696
583
  this.wssSendRefreshRequired();
697
584
  }
698
- /**
699
- * Registers the process handlers for uncaughtException, unhandledRejection, SIGINT and SIGTERM.
700
- * When either of these signals are received, the cleanup method is called with an appropriate message.
701
- */
702
585
  registerProcessHandlers() {
703
586
  this.log.debug(`Registering uncaughtException and unhandledRejection handlers...`);
704
587
  process.removeAllListeners('uncaughtException');
705
588
  process.removeAllListeners('unhandledRejection');
706
589
  this.exceptionHandler = async (error) => {
707
590
  this.log.fatal('Unhandled Exception detected at:', error.stack || error, rs);
708
- // await this.cleanup('Unhandled Exception detected, cleaning up...');
709
591
  };
710
592
  process.on('uncaughtException', this.exceptionHandler);
711
593
  this.rejectionHandler = async (reason, promise) => {
712
594
  this.log.fatal('Unhandled Rejection detected at:', promise, 'reason:', reason instanceof Error ? reason.stack : reason, rs);
713
- // await this.cleanup('Unhandled Rejection detected, cleaning up...');
714
595
  };
715
596
  process.on('unhandledRejection', this.rejectionHandler);
716
597
  this.log.debug(`Registering SIGINT and SIGTERM signal handlers...`);
@@ -723,9 +604,6 @@ export class Matterbridge extends EventEmitter {
723
604
  };
724
605
  process.on('SIGTERM', this.sigtermHandler);
725
606
  }
726
- /**
727
- * Deregisters the process uncaughtException, unhandledRejection, SIGINT and SIGTERM signal handlers.
728
- */
729
607
  deregisterProcesslHandlers() {
730
608
  this.log.debug(`Deregistering uncaughtException and unhandledRejection handlers...`);
731
609
  if (this.exceptionHandler)
@@ -742,11 +620,7 @@ export class Matterbridge extends EventEmitter {
742
620
  process.off('SIGTERM', this.sigtermHandler);
743
621
  this.sigtermHandler = undefined;
744
622
  }
745
- /**
746
- * Logs the node and system information.
747
- */
748
623
  async logNodeAndSystemInfo() {
749
- // IP address information
750
624
  const networkInterfaces = os.networkInterfaces();
751
625
  this.systemInformation.ipv4Address = '';
752
626
  this.systemInformation.ipv6Address = '';
@@ -766,7 +640,7 @@ export class Matterbridge extends EventEmitter {
766
640
  this.systemInformation.macAddress = detail.mac;
767
641
  }
768
642
  }
769
- if (this.systemInformation.ipv4Address !== '' /* && this.systemInformation.ipv6Address !== ''*/) {
643
+ if (this.systemInformation.ipv4Address !== '') {
770
644
  this.log.debug(`Using interface: '${this.systemInformation.interfaceName}'`);
771
645
  this.log.debug(`- with MAC address: '${this.systemInformation.macAddress}'`);
772
646
  this.log.debug(`- with IPv4 address: '${this.systemInformation.ipv4Address}'`);
@@ -774,22 +648,19 @@ export class Matterbridge extends EventEmitter {
774
648
  break;
775
649
  }
776
650
  }
777
- // Node information
778
651
  this.systemInformation.nodeVersion = process.versions.node;
779
652
  const versionMajor = parseInt(this.systemInformation.nodeVersion.split('.')[0]);
780
653
  const versionMinor = parseInt(this.systemInformation.nodeVersion.split('.')[1]);
781
654
  const versionPatch = parseInt(this.systemInformation.nodeVersion.split('.')[2]);
782
- // Host system information
783
655
  this.systemInformation.hostname = os.hostname();
784
656
  this.systemInformation.user = os.userInfo().username;
785
- this.systemInformation.osType = os.type(); // "Windows_NT", "Darwin", etc.
786
- this.systemInformation.osRelease = os.release(); // Kernel version
787
- this.systemInformation.osPlatform = os.platform(); // "win32", "linux", "darwin", etc.
788
- this.systemInformation.osArch = os.arch(); // "x64", "arm", etc.
789
- this.systemInformation.totalMemory = (os.totalmem() / 1024 / 1024 / 1024).toFixed(2) + ' GB'; // Convert to GB
790
- this.systemInformation.freeMemory = (os.freemem() / 1024 / 1024 / 1024).toFixed(2) + ' GB'; // Convert to GB
791
- this.systemInformation.systemUptime = (os.uptime() / 60 / 60).toFixed(2) + ' hours'; // Convert to hours
792
- // Log the system information
657
+ this.systemInformation.osType = os.type();
658
+ this.systemInformation.osRelease = os.release();
659
+ this.systemInformation.osPlatform = os.platform();
660
+ this.systemInformation.osArch = os.arch();
661
+ this.systemInformation.totalMemory = (os.totalmem() / 1024 / 1024 / 1024).toFixed(2) + ' GB';
662
+ this.systemInformation.freeMemory = (os.freemem() / 1024 / 1024 / 1024).toFixed(2) + ' GB';
663
+ this.systemInformation.systemUptime = (os.uptime() / 60 / 60).toFixed(2) + ' hours';
793
664
  this.log.debug('Host System Information:');
794
665
  this.log.debug(`- Hostname: ${this.systemInformation.hostname}`);
795
666
  this.log.debug(`- User: ${this.systemInformation.user}`);
@@ -805,19 +676,15 @@ export class Matterbridge extends EventEmitter {
805
676
  this.log.debug(`- Total Memory: ${this.systemInformation.totalMemory}`);
806
677
  this.log.debug(`- Free Memory: ${this.systemInformation.freeMemory}`);
807
678
  this.log.debug(`- System Uptime: ${this.systemInformation.systemUptime}`);
808
- // Home directory
809
679
  this.homeDirectory = getParameter('homedir') ?? os.homedir();
810
680
  this.matterbridgeInformation.homeDirectory = this.homeDirectory;
811
681
  this.log.debug(`Home Directory: ${this.homeDirectory}`);
812
- // Package root directory
813
682
  const currentFileDirectory = path.dirname(fileURLToPath(import.meta.url));
814
683
  this.rootDirectory = path.resolve(currentFileDirectory, '../');
815
684
  this.matterbridgeInformation.rootDirectory = this.rootDirectory;
816
685
  this.log.debug(`Root Directory: ${this.rootDirectory}`);
817
- // Global node_modules directory
818
686
  if (this.nodeContext)
819
687
  this.globalModulesDirectory = await this.nodeContext.get('globalModulesDirectory', '');
820
- // First run of Matterbridge so the node storage is empty
821
688
  if (this.globalModulesDirectory === '') {
822
689
  try {
823
690
  this.globalModulesDirectory = await this.getGlobalNodeModules();
@@ -841,7 +708,6 @@ export class Matterbridge extends EventEmitter {
841
708
  this.log.error(`Error getting global node_modules directory: ${error}`);
842
709
  });
843
710
  }
844
- // Create the data directory .matterbridge in the home directory
845
711
  this.matterbridgeDirectory = path.join(this.homeDirectory, '.matterbridge');
846
712
  this.matterbridgeInformation.matterbridgeDirectory = this.matterbridgeDirectory;
847
713
  try {
@@ -865,7 +731,6 @@ export class Matterbridge extends EventEmitter {
865
731
  }
866
732
  }
867
733
  this.log.debug(`Matterbridge Directory: ${this.matterbridgeDirectory}`);
868
- // Create the plugin directory Matterbridge in the home directory
869
734
  this.matterbridgePluginDirectory = path.join(this.homeDirectory, 'Matterbridge');
870
735
  this.matterbridgeInformation.matterbridgePluginDirectory = this.matterbridgePluginDirectory;
871
736
  try {
@@ -889,28 +754,19 @@ export class Matterbridge extends EventEmitter {
889
754
  }
890
755
  }
891
756
  this.log.debug(`Matterbridge Plugin Directory: ${this.matterbridgePluginDirectory}`);
892
- // Matterbridge version
893
757
  const packageJson = JSON.parse(await fs.readFile(path.join(this.rootDirectory, 'package.json'), 'utf-8'));
894
758
  this.matterbridgeVersion = packageJson.version;
895
759
  this.matterbridgeInformation.matterbridgeVersion = this.matterbridgeVersion;
896
760
  this.log.debug(`Matterbridge Version: ${this.matterbridgeVersion}`);
897
- // Matterbridge latest version
898
761
  if (this.nodeContext)
899
762
  this.matterbridgeLatestVersion = await this.nodeContext.get('matterbridgeLatestVersion', '');
900
763
  this.log.debug(`Matterbridge Latest Version: ${this.matterbridgeLatestVersion}`);
901
764
  this.getMatterbridgeLatestVersion();
902
- // Current working directory
903
765
  const currentDir = process.cwd();
904
766
  this.log.debug(`Current Working Directory: ${currentDir}`);
905
- // Command line arguments (excluding 'node' and the script name)
906
767
  const cmdArgs = process.argv.slice(2).join(' ');
907
768
  this.log.debug(`Command Line Arguments: ${cmdArgs}`);
908
769
  }
909
- /**
910
- * Retrieves the latest version of a package from the npm registry.
911
- * @param packageName - The name of the package.
912
- * @returns A Promise that resolves to the latest version of the package.
913
- */
914
770
  async getLatestVersion(packageName) {
915
771
  return new Promise((resolve, reject) => {
916
772
  this.execRunningCount++;
@@ -925,10 +781,6 @@ export class Matterbridge extends EventEmitter {
925
781
  });
926
782
  });
927
783
  }
928
- /**
929
- * Retrieves the path to the global Node.js modules directory.
930
- * @returns A promise that resolves to the path of the global Node.js modules directory.
931
- */
932
784
  async getGlobalNodeModules() {
933
785
  return new Promise((resolve, reject) => {
934
786
  this.execRunningCount++;
@@ -943,11 +795,6 @@ export class Matterbridge extends EventEmitter {
943
795
  });
944
796
  });
945
797
  }
946
- /**
947
- * Retrieves the latest version of Matterbridge and performs necessary actions based on the version comparison.
948
- * @private
949
- * @returns {Promise<void>} A promise that resolves when the latest version is retrieved and actions are performed.
950
- */
951
798
  async getMatterbridgeLatestVersion() {
952
799
  this.getLatestVersion('matterbridge')
953
800
  .then(async (matterbridgeLatestVersion) => {
@@ -964,19 +811,8 @@ export class Matterbridge extends EventEmitter {
964
811
  })
965
812
  .catch((error) => {
966
813
  this.log.error(`Error getting Matterbridge latest version: ${error.message}`);
967
- // error.stack && this.log.debug(error.stack);
968
814
  });
969
815
  }
970
- /**
971
- * Retrieves the latest version of a plugin and updates the plugin's latestVersion property.
972
- * If the plugin's version is different from the latest version, logs a warning message.
973
- * If the plugin's version is the same as the latest version, logs an info message.
974
- * If there is an error retrieving the latest version, logs an error message.
975
- *
976
- * @private
977
- * @param {RegisteredPlugin} plugin - The plugin for which to retrieve the latest version.
978
- * @returns {Promise<void>} A promise that resolves when the latest version is retrieved and actions are performed.
979
- */
980
816
  async getPluginLatestVersion(plugin) {
981
817
  this.getLatestVersion(plugin.name)
982
818
  .then(async (latestVersion) => {
@@ -988,54 +824,40 @@ export class Matterbridge extends EventEmitter {
988
824
  })
989
825
  .catch((error) => {
990
826
  this.log.error(`Error getting ${plg}${plugin.name}${er} latest version: ${error.message}`);
991
- // error.stack && this.log.debug(error.stack);
992
827
  });
993
828
  }
994
- /**
995
- * Creates a MatterLogger function to show the matter.js log messages in AnsiLogger (for the frontend).
996
- *
997
- * @returns {Function} The MatterLogger function.
998
- */
999
829
  createMatterLogger() {
1000
- const matterLogger = new AnsiLogger({ logName: 'Matter', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: "debug" /* LogLevel.DEBUG */ });
830
+ const matterLogger = new AnsiLogger({ logName: 'Matter', logTimestampFormat: 4, logLevel: "debug" });
1001
831
  return (_level, formattedLog) => {
1002
832
  const logger = formattedLog.slice(44, 44 + 20).trim();
1003
833
  const message = formattedLog.slice(65);
1004
834
  matterLogger.logName = logger;
1005
835
  switch (_level) {
1006
836
  case MatterLogLevel.DEBUG:
1007
- matterLogger.log("debug" /* LogLevel.DEBUG */, message);
837
+ matterLogger.log("debug", message);
1008
838
  break;
1009
839
  case MatterLogLevel.INFO:
1010
- matterLogger.log("info" /* LogLevel.INFO */, message);
840
+ matterLogger.log("info", message);
1011
841
  break;
1012
842
  case MatterLogLevel.NOTICE:
1013
- matterLogger.log("notice" /* LogLevel.NOTICE */, message);
843
+ matterLogger.log("notice", message);
1014
844
  break;
1015
845
  case MatterLogLevel.WARN:
1016
- matterLogger.log("warn" /* LogLevel.WARN */, message);
846
+ matterLogger.log("warn", message);
1017
847
  break;
1018
848
  case MatterLogLevel.ERROR:
1019
- matterLogger.log("error" /* LogLevel.ERROR */, message);
849
+ matterLogger.log("error", message);
1020
850
  break;
1021
851
  case MatterLogLevel.FATAL:
1022
- matterLogger.log("fatal" /* LogLevel.FATAL */, message);
852
+ matterLogger.log("fatal", message);
1023
853
  break;
1024
854
  default:
1025
- matterLogger.log("debug" /* LogLevel.DEBUG */, message);
855
+ matterLogger.log("debug", message);
1026
856
  break;
1027
857
  }
1028
858
  };
1029
859
  }
1030
- /**
1031
- * Creates a Matter File Logger.
1032
- *
1033
- * @param {string} filePath - The path to the log file.
1034
- * @param {boolean} [unlink=false] - Whether to unlink the log file before creating a new one.
1035
- * @returns {Function} - A function that logs formatted messages to the log file.
1036
- */
1037
860
  async createMatterFileLogger(filePath, unlink = false) {
1038
- // 2024-08-21 08:55:19.488 DEBUG InteractionMessenger Sending DataReport chunk with 28 attributes and 0 events: 1004 bytes
1039
861
  let fileSize = 0;
1040
862
  if (unlink) {
1041
863
  try {
@@ -1084,83 +906,53 @@ export class Matterbridge extends EventEmitter {
1084
906
  }
1085
907
  };
1086
908
  }
1087
- /**
1088
- * Update matterbridge and cleanup.
1089
- */
1090
909
  async updateProcess() {
1091
910
  await this.cleanup('updating...', false);
1092
911
  }
1093
- /**
1094
- * Restarts the process by spawning a new process and exiting the current process.
1095
- */
1096
912
  async restartProcess() {
1097
913
  await this.cleanup('restarting...', true);
1098
914
  }
1099
- /**
1100
- * Shut down the process by exiting the current process.
1101
- */
1102
915
  async shutdownProcess() {
1103
916
  await this.cleanup('shutting down...', false);
1104
917
  }
1105
- /**
1106
- * Shut down the process and reset.
1107
- */
1108
918
  async unregisterAndShutdownProcess() {
1109
919
  this.log.info('Unregistering all devices and shutting down...');
1110
- for (const plugin of this.plugins /* .filter((plugin) => plugin.enabled && !plugin.error))*/) {
920
+ for (const plugin of this.plugins) {
1111
921
  await this.removeAllBridgedDevices(plugin.name);
1112
922
  }
1113
923
  await this.cleanup('unregistered all devices and shutting down...', false);
1114
924
  }
1115
- /**
1116
- * Shut down the process and reset.
1117
- */
1118
925
  async shutdownProcessAndReset() {
1119
926
  await this.cleanup('shutting down with reset...', false);
1120
927
  }
1121
- /**
1122
- * Shut down the process and factory reset.
1123
- */
1124
928
  async shutdownProcessAndFactoryReset() {
1125
929
  await this.cleanup('shutting down with factory reset...', false);
1126
930
  }
1127
- /**
1128
- * Cleans up the Matterbridge instance.
1129
- * @param message - The cleanup message.
1130
- * @param restart - Indicates whether to restart the instance after cleanup. Default is `false`.
1131
- * @returns A promise that resolves when the cleanup is completed.
1132
- */
1133
931
  async cleanup(message, restart = false) {
1134
932
  if (this.initialized && !this.hasCleanupStarted) {
1135
933
  this.hasCleanupStarted = true;
1136
934
  this.log.info(message);
1137
- // Deregisters the process handlers
1138
935
  this.deregisterProcesslHandlers();
1139
- // Clear the start matter interval
1140
936
  if (this.startMatterInterval) {
1141
937
  clearInterval(this.startMatterInterval);
1142
938
  this.startMatterInterval = undefined;
1143
939
  this.log.debug('Start matter interval cleared');
1144
940
  }
1145
- // Clear the check update interval
1146
941
  if (this.checkUpdateInterval) {
1147
942
  clearInterval(this.checkUpdateInterval);
1148
943
  this.checkUpdateInterval = undefined;
1149
944
  this.log.debug('Check update interval cleared');
1150
945
  }
1151
- // Clear the configure timeout
1152
946
  if (this.configureTimeout) {
1153
947
  clearTimeout(this.configureTimeout);
1154
948
  this.configureTimeout = undefined;
1155
949
  this.log.debug('Matterbridge configure timeout cleared');
1156
950
  }
1157
- // Clear the reachability timeout
1158
951
  if (this.reachabilityTimeout) {
1159
952
  clearTimeout(this.reachabilityTimeout);
1160
953
  this.reachabilityTimeout = undefined;
1161
954
  this.log.debug('Matterbridge reachability timeout cleared');
1162
955
  }
1163
- // Calling the shutdown method of each plugin and clear the reachability timeout
1164
956
  for (const plugin of this.plugins) {
1165
957
  if (!plugin.enabled || plugin.error)
1166
958
  continue;
@@ -1171,29 +963,24 @@ export class Matterbridge extends EventEmitter {
1171
963
  this.log.debug(`Plugin ${plg}${plugin.name}${db} reachability timeout cleared`);
1172
964
  }
1173
965
  }
1174
- // Close the http server
1175
966
  if (this.httpServer) {
1176
967
  this.httpServer.close();
1177
968
  this.httpServer.removeAllListeners();
1178
969
  this.httpServer = undefined;
1179
970
  this.log.debug('Frontend http server closed successfully');
1180
971
  }
1181
- // Close the https server
1182
972
  if (this.httpsServer) {
1183
973
  this.httpsServer.close();
1184
974
  this.httpsServer.removeAllListeners();
1185
975
  this.httpsServer = undefined;
1186
976
  this.log.debug('Frontend https server closed successfully');
1187
977
  }
1188
- // Remove listeners from the express app
1189
978
  if (this.expressApp) {
1190
979
  this.expressApp.removeAllListeners();
1191
980
  this.expressApp = undefined;
1192
981
  this.log.debug('Frontend app closed successfully');
1193
982
  }
1194
- // Close the WebSocket server
1195
983
  if (this.webSocketServer) {
1196
- // Close all active connections
1197
984
  this.webSocketServer.clients.forEach((client) => {
1198
985
  if (client.readyState === WebSocket.OPEN) {
1199
986
  client.close();
@@ -1209,35 +996,29 @@ export class Matterbridge extends EventEmitter {
1209
996
  });
1210
997
  this.webSocketServer = undefined;
1211
998
  }
1212
- // Closing matter
999
+ if (!hasParameter('nostorageconversion') && this.edge === false && this.matterbridgeContext && ['updating...', 'restarting...', 'shutting down...'].includes(message)) {
1000
+ await this.convertStorage(this.matterbridgeContext, 'Mattebridge');
1001
+ }
1213
1002
  await this.stopMatterServer();
1214
- // Closing matter storage
1215
1003
  await this.stopMatterStorage();
1216
- // Remove the matterfilelogger
1217
1004
  try {
1218
1005
  Logger.removeLogger('matterfilelogger');
1219
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1220
1006
  }
1221
1007
  catch (error) {
1222
- // this.log.debug(`Error removing the matterfilelogger for file ${CYAN}${path.join(this.matterbridgeDirectory, this.matterLoggerFile)}${er}: ${error instanceof Error ? error.message : error}`);
1223
1008
  }
1224
- // Serialize registeredDevices
1225
1009
  if (this.nodeStorage && this.nodeContext) {
1226
1010
  this.log.info('Saving registered devices...');
1227
1011
  const serializedRegisteredDevices = [];
1228
1012
  this.devices.forEach(async (device) => {
1229
1013
  const serializedMatterbridgeDevice = device.serialize();
1230
- // this.log.info(`- ${serializedMatterbridgeDevice.deviceName}${rs}\n`, serializedMatterbridgeDevice);
1231
1014
  if (serializedMatterbridgeDevice)
1232
1015
  serializedRegisteredDevices.push(serializedMatterbridgeDevice);
1233
1016
  });
1234
1017
  await this.nodeContext.set('devices', serializedRegisteredDevices);
1235
1018
  this.log.info(`Saved registered devices (${serializedRegisteredDevices?.length})`);
1236
- // Clear nodeContext and nodeStorage (they just need 1000ms to write the data to disk)
1237
1019
  this.log.debug(`Closing node storage context for ${plg}Matterbridge${db}...`);
1238
1020
  await this.nodeContext.close();
1239
1021
  this.nodeContext = undefined;
1240
- // Clear nodeContext for each plugin (they just need 1000ms to write the data to disk)
1241
1022
  for (const plugin of this.plugins) {
1242
1023
  if (plugin.nodeContext) {
1243
1024
  this.log.debug(`Closing node storage context for plugin ${plg}${plugin.name}${db}...`);
@@ -1268,16 +1049,13 @@ export class Matterbridge extends EventEmitter {
1268
1049
  }
1269
1050
  else {
1270
1051
  if (message === 'shutting down with reset...') {
1271
- // Delete matter storage file
1272
1052
  this.log.info('Resetting Matterbridge commissioning information...');
1273
1053
  await fs.unlink(path.join(this.matterbridgeDirectory, this.matterStorageName));
1274
1054
  this.log.info('Reset done! Remove all paired devices from the controllers.');
1275
1055
  }
1276
1056
  if (message === 'shutting down with factory reset...') {
1277
- // Delete matter storage file
1278
1057
  this.log.info('Resetting Matterbridge commissioning information...');
1279
1058
  await fs.unlink(path.join(this.matterbridgeDirectory, this.matterStorageName));
1280
- // Delete node storage directory with its subdirectories
1281
1059
  this.log.info('Resetting Matterbridge storage...');
1282
1060
  await fs.rm(path.join(this.matterbridgeDirectory, this.nodeStorageName), { recursive: true });
1283
1061
  this.log.info('Factory reset done! Remove all paired devices from the controllers.');
@@ -1290,33 +1068,19 @@ export class Matterbridge extends EventEmitter {
1290
1068
  this.initialized = false;
1291
1069
  }
1292
1070
  }
1293
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1294
1071
  async addBridgedEndpoint(pluginName, device) {
1295
- // Nothing to do here
1296
1072
  }
1297
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1298
1073
  async removeBridgedEndpoint(pluginName, device) {
1299
- // Nothing to do here
1300
1074
  }
1301
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1302
1075
  async removeAllBridgedEndpoints(pluginName) {
1303
- // Nothing to do here
1304
1076
  }
1305
- /**
1306
- * Adds a bridged device to the Matterbridge.
1307
- * @param pluginName - The name of the plugin.
1308
- * @param device - The bridged device to add.
1309
- * @returns {Promise<void>} - A promise that resolves when the device is added.
1310
- */
1311
1077
  async addBridgedDevice(pluginName, device) {
1312
1078
  this.log.debug(`Adding bridged device ${dev}${device.deviceName}${db} (${zb}${device.name}${db}) for plugin ${plg}${pluginName}${db}`);
1313
- // Check if the plugin is registered
1314
1079
  const plugin = this.plugins.get(pluginName);
1315
1080
  if (!plugin) {
1316
1081
  this.log.error(`Error adding bridged device ${dev}${device.deviceName}${er} (${zb}${device.name}${er}) plugin ${plg}${pluginName}${er} not found`);
1317
1082
  return;
1318
1083
  }
1319
- // Register and add the device to matterbridge aggregator in bridge mode
1320
1084
  if (this.bridgeMode === 'bridge') {
1321
1085
  if (!this.matterAggregator) {
1322
1086
  this.log.error(`Adding bridged device ${dev}${device.deviceName}${er} (${zb}${device.name}${er}) for plugin ${plg}${pluginName}${er} error: matterAggregator not found`);
@@ -1324,11 +1088,8 @@ export class Matterbridge extends EventEmitter {
1324
1088
  }
1325
1089
  this.matterAggregator.addBridgedDevice(device);
1326
1090
  }
1327
- // The first time create the commissioning server and the aggregator for DynamicPlatform
1328
- // Register and add the device in childbridge mode
1329
1091
  if (this.bridgeMode === 'childbridge') {
1330
1092
  if (plugin.type === 'AccessoryPlatform') {
1331
- // Check if the plugin is locked with the commissioning server
1332
1093
  if (!plugin.locked) {
1333
1094
  plugin.locked = true;
1334
1095
  plugin.storageContext = await this.importCommissioningServerContext(plugin.name, device);
@@ -1342,7 +1103,6 @@ export class Matterbridge extends EventEmitter {
1342
1103
  }
1343
1104
  }
1344
1105
  if (plugin.type === 'DynamicPlatform') {
1345
- // Check if the plugin is locked with the commissioning server and the aggregator
1346
1106
  if (!plugin.locked) {
1347
1107
  plugin.locked = true;
1348
1108
  this.log.debug(`Creating commissioning server context for ${plg}${plugin.name}${db}`);
@@ -1363,25 +1123,16 @@ export class Matterbridge extends EventEmitter {
1363
1123
  plugin.registeredDevices++;
1364
1124
  if (plugin.addedDevices !== undefined)
1365
1125
  plugin.addedDevices++;
1366
- // Add the device to the DeviceManager
1367
1126
  this.devices.set(device);
1368
1127
  this.log.info(`Added and registered bridged device (${plugin.registeredDevices}/${plugin.addedDevices}) ${dev}${device.deviceName}${nf} (${dev}${device.name}${nf}) for plugin ${plg}${pluginName}${nf}`);
1369
1128
  }
1370
- /**
1371
- * Removes a bridged device from the Matterbridge.
1372
- * @param pluginName - The name of the plugin.
1373
- * @param device - The device to be removed.
1374
- * @returns A Promise that resolves when the device is successfully removed.
1375
- */
1376
1129
  async removeBridgedDevice(pluginName, device) {
1377
1130
  this.log.debug(`Removing bridged device ${dev}${device.deviceName}${db} (${zb}${device.name}${db}) for plugin ${plg}${pluginName}${db}`);
1378
- // Check if the plugin is registered
1379
1131
  const plugin = this.plugins.get(pluginName);
1380
1132
  if (!plugin) {
1381
1133
  this.log.error(`Error removing bridged device ${dev}${device.deviceName}${er} (${zb}${device.name}${er}) for plugin ${plg}${pluginName}${er}: plugin not found`);
1382
1134
  return;
1383
1135
  }
1384
- // Remove the device from matterbridge aggregator in bridge mode
1385
1136
  if (this.bridgeMode === 'bridge') {
1386
1137
  if (!this.matterAggregator) {
1387
1138
  this.log.error(`Error removing bridged device ${dev}${device.deviceName}${er} (${zb}${device.name}${er}) for plugin ${plg}${pluginName}${er}: matterAggregator not found`);
@@ -1391,8 +1142,6 @@ export class Matterbridge extends EventEmitter {
1391
1142
  device.setBridgedDeviceReachability(false);
1392
1143
  device.getClusterServerById(BridgedDeviceBasicInformation.Cluster.id)?.triggerReachableChangedEvent({ reachableNewValue: false });
1393
1144
  }
1394
- // device.getClusterServerById(BridgedDeviceBasicInformation.Cluster.id)?.triggerShutDownEvent({});
1395
- // device.getClusterServerById(BridgedDeviceBasicInformation.Cluster.id)?.triggerLeaveEvent({});
1396
1145
  this.matterAggregator?.removeBridgedDevice(device);
1397
1146
  this.log.info(`Removed bridged device(${plugin.registeredDevices}/${plugin.addedDevices}) ${dev}${device.deviceName}${nf} (${zb}${device.name}${nf}) for plugin ${plg}${pluginName}${nf}`);
1398
1147
  if (plugin.registeredDevices !== undefined)
@@ -1400,7 +1149,6 @@ export class Matterbridge extends EventEmitter {
1400
1149
  if (plugin.addedDevices !== undefined)
1401
1150
  plugin.addedDevices--;
1402
1151
  }
1403
- // Remove the device in childbridge mode
1404
1152
  if (this.bridgeMode === 'childbridge') {
1405
1153
  if (plugin.type === 'AccessoryPlatform') {
1406
1154
  if (!plugin.commissioningServer) {
@@ -1424,22 +1172,14 @@ export class Matterbridge extends EventEmitter {
1424
1172
  plugin.registeredDevices--;
1425
1173
  if (plugin.addedDevices !== undefined)
1426
1174
  plugin.addedDevices--;
1427
- // Remove the commissioning server
1428
1175
  if (plugin.registeredDevices === 0 && plugin.addedDevices === 0 && plugin.commissioningServer) {
1429
1176
  this.matterServer?.removeCommissioningServer(plugin.commissioningServer);
1430
1177
  plugin.commissioningServer = undefined;
1431
1178
  this.log.info(`Removed commissioning server for plugin ${plg}${pluginName}${nf}`);
1432
1179
  }
1433
1180
  }
1434
- // Remove the device from the DeviceManager
1435
1181
  this.devices.remove(device);
1436
1182
  }
1437
- /**
1438
- * Removes all bridged devices associated with a specific plugin.
1439
- *
1440
- * @param pluginName - The name of the plugin.
1441
- * @returns A promise that resolves when all devices have been removed.
1442
- */
1443
1183
  async removeAllBridgedDevices(pluginName) {
1444
1184
  this.log.debug(`Removing all bridged devices for plugin ${plg}${pluginName}${db}`);
1445
1185
  this.devices.forEach(async (device) => {
@@ -1448,13 +1188,7 @@ export class Matterbridge extends EventEmitter {
1448
1188
  }
1449
1189
  });
1450
1190
  }
1451
- /**
1452
- * Starts the Matterbridge in bridge mode.
1453
- * @private
1454
- * @returns {Promise<void>} A promise that resolves when the Matterbridge is started.
1455
- */
1456
1191
  async startBridge() {
1457
- // Plugins are configured by a timer when matter server is started and plugin.configured is set to true
1458
1192
  if (!this.storageManager)
1459
1193
  throw new Error('No storage manager initialized');
1460
1194
  if (!this.matterbridgeContext)
@@ -1473,7 +1207,6 @@ export class Matterbridge extends EventEmitter {
1473
1207
  let failCount = 0;
1474
1208
  this.startMatterInterval = setInterval(async () => {
1475
1209
  for (const plugin of this.plugins) {
1476
- // new code to not start the bridge if one plugin is in error cause the controllers will delete the devices loosing all the configuration
1477
1210
  if (!plugin.enabled)
1478
1211
  continue;
1479
1212
  if (plugin.error) {
@@ -1498,18 +1231,15 @@ export class Matterbridge extends EventEmitter {
1498
1231
  clearInterval(this.startMatterInterval);
1499
1232
  this.startMatterInterval = undefined;
1500
1233
  this.log.debug('Cleared startMatterInterval interval for Matterbridge');
1501
- // Start the Matter server
1502
1234
  await this.startMatterServer();
1503
1235
  this.log.notice('Matter server started');
1504
- // Show the QR code for commissioning or log the already commissioned message
1505
1236
  await this.showCommissioningQRCode(this.commissioningServer, this.matterbridgeContext, this.nodeContext, 'Matterbridge');
1506
- // Configure the plugins
1507
1237
  this.configureTimeout = setTimeout(async () => {
1508
1238
  for (const plugin of this.plugins) {
1509
1239
  if (!plugin.enabled || !plugin.loaded || !plugin.started || plugin.error)
1510
1240
  continue;
1511
1241
  try {
1512
- await this.plugins.configure(plugin); // TODO No await do it in parallel
1242
+ await this.plugins.configure(plugin);
1513
1243
  }
1514
1244
  catch (error) {
1515
1245
  plugin.error = true;
@@ -1518,7 +1248,6 @@ export class Matterbridge extends EventEmitter {
1518
1248
  }
1519
1249
  this.wssSendRefreshRequired();
1520
1250
  }, 30 * 1000);
1521
- // Setting reachability to true
1522
1251
  this.reachabilityTimeout = setTimeout(() => {
1523
1252
  this.log.info(`Setting reachability to true for ${plg}Matterbridge${db}`);
1524
1253
  if (this.commissioningServer)
@@ -1528,14 +1257,7 @@ export class Matterbridge extends EventEmitter {
1528
1257
  }, 60 * 1000);
1529
1258
  }, 1000);
1530
1259
  }
1531
- /**
1532
- * Starts the Matterbridge in childbridge mode.
1533
- * @private
1534
- * @returns {Promise<void>} A promise that resolves when the Matterbridge is started.
1535
- */
1536
1260
  async startChildbridge() {
1537
- // Matterbridge.addBridgedDevice creates the commissionig servers and add the devices to the the commissioning server or to the aggregator
1538
- // Plugins are configured by a timer when matter server is started and plugin.configured is set to true
1539
1261
  if (!this.storageManager)
1540
1262
  throw new Error('No storage manager initialized');
1541
1263
  this.matterServer = this.createMatterServer(this.storageManager);
@@ -1545,7 +1267,6 @@ export class Matterbridge extends EventEmitter {
1545
1267
  this.startMatterInterval = setInterval(async () => {
1546
1268
  let allStarted = true;
1547
1269
  for (const plugin of this.plugins) {
1548
- // new code to not start the bridge if one plugin is in error cause the controllers will delete the devices loosing all the configuration
1549
1270
  if (!plugin.enabled)
1550
1271
  continue;
1551
1272
  if (plugin.error) {
@@ -1573,16 +1294,14 @@ export class Matterbridge extends EventEmitter {
1573
1294
  clearInterval(this.startMatterInterval);
1574
1295
  this.startMatterInterval = undefined;
1575
1296
  this.log.debug('Cleared startMatterInterval interval in childbridge mode');
1576
- // Start the Matter server
1577
1297
  await this.startMatterServer();
1578
1298
  this.log.notice('Matter server started');
1579
- // Configure the plugins
1580
1299
  this.configureTimeout = setTimeout(async () => {
1581
1300
  for (const plugin of this.plugins) {
1582
1301
  if (!plugin.enabled || !plugin.loaded || !plugin.started || plugin.error)
1583
1302
  continue;
1584
1303
  try {
1585
- await this.plugins.configure(plugin); // TODO No await do it in parallel
1304
+ await this.plugins.configure(plugin);
1586
1305
  }
1587
1306
  catch (error) {
1588
1307
  plugin.error = true;
@@ -1611,7 +1330,6 @@ export class Matterbridge extends EventEmitter {
1611
1330
  continue;
1612
1331
  }
1613
1332
  await this.showCommissioningQRCode(plugin.commissioningServer, plugin.storageContext, plugin.nodeContext, plugin.name);
1614
- // Setting reachability to true
1615
1333
  plugin.reachabilityTimeout = setTimeout(() => {
1616
1334
  this.log.info(`Setting reachability to true for ${plg}${plugin.name}${db}`);
1617
1335
  if (plugin.commissioningServer)
@@ -1624,11 +1342,6 @@ export class Matterbridge extends EventEmitter {
1624
1342
  }
1625
1343
  }, 1000);
1626
1344
  }
1627
- /**
1628
- * Starts the Matterbridge controller.
1629
- * @private
1630
- * @returns {Promise<void>} A promise that resolves when the Matterbridge is started.
1631
- */
1632
1345
  async startController() {
1633
1346
  if (!this.storageManager) {
1634
1347
  this.log.error('No storage manager initialized');
@@ -1691,7 +1404,7 @@ export class Matterbridge extends EventEmitter {
1691
1404
  const nodeId = await this.commissioningController.commissionNode(options);
1692
1405
  this.log.info(`Commissioning successfully done with nodeId: ${nodeId}`);
1693
1406
  this.log.info('ActiveSessionInformation:', this.commissioningController.getActiveSessionInformation());
1694
- } // (hasParameter('pairingcode'))
1407
+ }
1695
1408
  if (hasParameter('unpairall')) {
1696
1409
  this.log.info('***Commissioning controller unpairing all nodes...');
1697
1410
  const nodeIds = this.commissioningController.getCommissionedNodes();
@@ -1702,8 +1415,6 @@ export class Matterbridge extends EventEmitter {
1702
1415
  return;
1703
1416
  }
1704
1417
  if (hasParameter('discover')) {
1705
- // const discover = await this.commissioningController.discoverCommissionableDevices({ productId: 0x8000, deviceType: 0xfff1 });
1706
- // console.log(discover);
1707
1418
  }
1708
1419
  if (!this.commissioningController.isCommissioned()) {
1709
1420
  this.log.info('***Commissioning controller is not commissioned: use matterbridge -controller -pairingcode [pairingcode] to commission a device');
@@ -1744,12 +1455,10 @@ export class Matterbridge extends EventEmitter {
1744
1455
  },
1745
1456
  });
1746
1457
  node.logStructure();
1747
- // Get the interaction client
1748
1458
  this.log.info('Getting the interaction client');
1749
1459
  const interactionClient = await node.getInteractionClient();
1750
1460
  let cluster;
1751
1461
  let attributes;
1752
- // Log BasicInformationCluster
1753
1462
  cluster = BasicInformationCluster;
1754
1463
  attributes = await interactionClient.getMultipleAttributes({
1755
1464
  attributes: [{ clusterId: cluster.id }],
@@ -1759,7 +1468,6 @@ export class Matterbridge extends EventEmitter {
1759
1468
  attributes.forEach((attribute) => {
1760
1469
  this.log.info(`- 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
1470
  });
1762
- // Log PowerSourceCluster
1763
1471
  cluster = PowerSourceCluster;
1764
1472
  attributes = await interactionClient.getMultipleAttributes({
1765
1473
  attributes: [{ clusterId: cluster.id }],
@@ -1769,7 +1477,6 @@ export class Matterbridge extends EventEmitter {
1769
1477
  attributes.forEach((attribute) => {
1770
1478
  this.log.info(`- 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}`);
1771
1479
  });
1772
- // Log ThreadNetworkDiagnostics
1773
1480
  cluster = ThreadNetworkDiagnosticsCluster;
1774
1481
  attributes = await interactionClient.getMultipleAttributes({
1775
1482
  attributes: [{ clusterId: cluster.id }],
@@ -1779,7 +1486,6 @@ export class Matterbridge extends EventEmitter {
1779
1486
  attributes.forEach((attribute) => {
1780
1487
  this.log.info(`- 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}`);
1781
1488
  });
1782
- // Log SwitchCluster
1783
1489
  cluster = SwitchCluster;
1784
1490
  attributes = await interactionClient.getMultipleAttributes({
1785
1491
  attributes: [{ clusterId: cluster.id }],
@@ -1800,15 +1506,6 @@ export class Matterbridge extends EventEmitter {
1800
1506
  this.log.info('Subscribed to all attributes and events');
1801
1507
  }
1802
1508
  }
1803
- /** ***********************************************************************************************************************************/
1804
- /** Matter.js methods */
1805
- /** ***********************************************************************************************************************************/
1806
- /**
1807
- * Starts the matter storage process based on the specified storage type and name.
1808
- * @param {string} storageType - The type of storage to start (e.g., 'disk', 'json').
1809
- * @param {string} storageName - The name of the storage file.
1810
- * @returns {Promise<void>} - A promise that resolves when the storage process is started.
1811
- */
1812
1509
  async startMatterStorage(storageType, storageName) {
1813
1510
  this.log.debug(`Starting matter ${storageType} storage ${CYAN}${storageName}${db}`);
1814
1511
  if (storageType === 'disk') {
@@ -1852,14 +1549,174 @@ export class Matterbridge extends EventEmitter {
1852
1549
  }
1853
1550
  }
1854
1551
  this.log.debug(`Creating commissioning server context for ${plg}Matterbridge${db}`);
1855
- this.matterbridgeContext = await this.createCommissioningServerContext('Matterbridge', 'Matterbridge', DeviceTypes.AGGREGATOR.code, 0xfff1, 'Matterbridge', 0x8000, 'Matterbridge aggregator');
1552
+ this.matterbridgeContext = await this.createCommissioningServerContext('Matterbridge', 'Matterbridge', aggregator.code, 0xfff1, 'Matterbridge', 0x8000, 'Matterbridge aggregator');
1553
+ await this.matterbridgeContext.set('port', this.port);
1554
+ await this.matterbridgeContext.set('passcode', this.passcode);
1555
+ await this.matterbridgeContext.set('discriminator', this.discriminator);
1556
+ }
1557
+ async convertStorage(context, pluginName) {
1558
+ try {
1559
+ const storageService = Environment.default.get(StorageService);
1560
+ Environment.default.vars.set('path.root', path.join(this.matterbridgeDirectory, 'matterstorage' + (this.profile ? '.' + this.profile : '')));
1561
+ const nodeStorage = await storageService.open('Matterbridge');
1562
+ if ((await nodeStorage.createContext('root').createContext('generalDiagnostics').get('rebootCount', -1)) >= 0) {
1563
+ this.log.info(`Matter node storage already converted to Matterbridge edge for ${plg}${pluginName}${nf}`);
1564
+ return;
1565
+ }
1566
+ else {
1567
+ this.log.notice(`Converting matter node storage to Matterbridge edge for ${plg}${pluginName}${nt}...`);
1568
+ }
1569
+ const fabricManagerContext = context.createContext('FabricManager');
1570
+ const fabrics = (await fabricManagerContext.get('fabrics', []));
1571
+ const nextFabricIndex = await fabricManagerContext.get('nextFabricIndex', 0);
1572
+ const eventHandlerContext = context.createContext('EventHandler');
1573
+ const sessionManagerContext = context.createContext('SessionManager');
1574
+ const endpointStructureContext = context.createContext('EndpointStructure');
1575
+ const generalCommissioningContext = context.createContext('Cluster-0-48');
1576
+ const basicInformationContext = context.createContext('Cluster-0-40');
1577
+ const fabricInfo = {};
1578
+ const fabricInfoArray = [];
1579
+ const nocArray = [];
1580
+ const trcArray = [];
1581
+ const aclArray = [];
1582
+ this.log.info(`Found ${CYAN}${fabrics.length}${nf} fabrics (nextFabricIndex ${CYAN}${nextFabricIndex}${nf}) for ${plg}${pluginName}${nf}:`);
1583
+ if (fabrics.length === 0 || nextFabricIndex === 0) {
1584
+ this.log.notice(`If you want to try out matterbridge edge (beta) add -edge to the command line and pair it to your controller(s).`);
1585
+ return;
1586
+ }
1587
+ for (const fabric of fabrics) {
1588
+ this.log.info(`- fabricIndex ${CYAN}${fabric.fabricIndex}${nf} fabricId ${CYAN}${fabric.fabricId}${nf} nodeId ${CYAN}${fabric.nodeId}${nf} rootNodeId ${CYAN}${fabric.rootNodeId}${nf} rootVendorId ${CYAN}${fabric.rootVendorId}${nf} label ${CYAN}${fabric.label}${nf}`);
1589
+ fabricInfo[fabric.fabricIndex] = {
1590
+ fabricIndex: fabric.fabricIndex,
1591
+ fabricId: fabric.fabricId,
1592
+ nodeId: fabric.nodeId,
1593
+ rootNodeId: fabric.rootNodeId,
1594
+ rootVendorId: fabric.rootVendorId,
1595
+ label: fabric.label,
1596
+ };
1597
+ fabricInfoArray.push({
1598
+ fabricIndex: fabric.fabricIndex,
1599
+ fabricId: fabric.fabricId,
1600
+ nodeId: fabric.nodeId,
1601
+ vendorId: fabric.rootVendorId,
1602
+ rootPublicKey: fabric.rootPublicKey,
1603
+ label: fabric.label,
1604
+ });
1605
+ nocArray.push({ noc: fabric.operationalCert, icac: null, fabricIndex: fabric.fabricIndex });
1606
+ trcArray.push('{\"__object__\":\"Uint8Array\",\"__value__\":\"' + Buffer.from(fabric.rootCert).toString('hex') + '\"}');
1607
+ this.log.info(`- updating ACL for fabricIndex ${fabric.fabricIndex}:`, fabric.scopedClusterData);
1608
+ const acl = fabric.scopedClusterData.get(0x1f)?.get('acl');
1609
+ if (acl && acl.value.length > 0) {
1610
+ aclArray.push(acl.value[0]);
1611
+ this.log.info(`- ACL updated to ${debugStringify(acl.value)}${nf} for fabricIndex ${CYAN}${fabric.fabricIndex}${nf}`);
1612
+ }
1613
+ else {
1614
+ const defaultAcl = { fabricIndex: fabric.fabricIndex, privilege: 5, authMode: 2, subjects: [fabric.rootNodeId], targets: null };
1615
+ aclArray.push(defaultAcl);
1616
+ this.log.info(`- ACL updated to default ${debugStringify(defaultAcl)}${nf} for fabricIndex ${CYAN}${fabric.fabricIndex}${nf}`);
1617
+ }
1618
+ }
1619
+ await nodeStorage.createContext('fabrics').set('fabrics', fabrics);
1620
+ await nodeStorage.createContext('fabrics').set('nextFabricIndex', nextFabricIndex);
1621
+ await nodeStorage.createContext('sessions').set('resumptionRecords', await sessionManagerContext.get('resumptionRecords', []));
1622
+ await nodeStorage.createContext('events').set('lastEventNumber', await eventHandlerContext.get('lastEventNumber', 1));
1623
+ await nodeStorage.createContext('root').set('__number__', 0);
1624
+ await nodeStorage.createContext('root').createContext('parts').createContext('Matterbridge').set('__number__', 1);
1625
+ await nodeStorage.createContext('root').createContext('commissioning').set('enabled', true);
1626
+ await nodeStorage.createContext('root').createContext('commissioning').set('commissioned', true);
1627
+ await nodeStorage.createContext('root').createContext('commissioning').set('fabrics', fabricInfo);
1628
+ await nodeStorage.createContext('root').createContext('operationalCredentials').set('commissionedFabrics', fabricInfoArray.length);
1629
+ await nodeStorage.createContext('root').createContext('operationalCredentials').set('fabrics', fabricInfoArray);
1630
+ await nodeStorage.createContext('root').createContext('operationalCredentials').set('nocs', nocArray);
1631
+ await nodeStorage.createContext('root').createContext('operationalCredentials').set('trustedRootCertificates', trcArray);
1632
+ await nodeStorage.createContext('root').createContext('accessControl').set('acl', aclArray);
1633
+ await nodeStorage
1634
+ .createContext('root')
1635
+ .createContext('generalCommissioning')
1636
+ .set('breadcrumb', await generalCommissioningContext.get('breadcrumb', BigInt(0)));
1637
+ await nodeStorage
1638
+ .createContext('root')
1639
+ .createContext('basicInformation')
1640
+ .set('location', await basicInformationContext.get('location', 'XX'));
1641
+ await nodeStorage.createContext('root').createContext('network').set('ble', false);
1642
+ await nodeStorage.createContext('root').createContext('network').set('operationalPort', 5540);
1643
+ await nodeStorage.createContext('root').createContext('productDescription').set('productId', 0x8000);
1644
+ await nodeStorage.createContext('root').createContext('productDescription').set('vendorId', 0xfff1);
1645
+ for (const key of await endpointStructureContext.keys()) {
1646
+ if (key === 'nextEndpointId') {
1647
+ await nodeStorage.createContext('root').set('__nextNumber__', await endpointStructureContext.get(key));
1648
+ continue;
1649
+ }
1650
+ const parts = key.split('-');
1651
+ const number = await endpointStructureContext.get(key);
1652
+ if (parts.length === 2) {
1653
+ this.log.debug(`Converting bridge Matterbridge.EndpointStructure:${key}:${number} to root.parts.Matterbridge.__number__:${CYAN}${number}${db}`);
1654
+ await nodeStorage.createContext('root').createContext('parts').createContext('Matterbridge').set('__number__', number);
1655
+ }
1656
+ else if (parts.length === 3 && parts[2].startsWith('unique_')) {
1657
+ const device = this.devices.get(parts[2].replace('unique_', ''));
1658
+ if (device && device.deviceName && device.maybeNumber) {
1659
+ this.log.debug(`Converting unique Matterbridge.EndpointStructure:${key}:${number} to root.parts.Matterbridge.parts.${device.deviceName.replace(/[ .]/g, '')}.__number__:${CYAN}${device.maybeNumber}${db}`);
1660
+ await nodeStorage.createContext('root').createContext('parts').createContext('Matterbridge').createContext('parts').createContext(device.deviceName.replace(/[ .]/g, '')).set('__number__', device.maybeNumber);
1661
+ }
1662
+ }
1663
+ else if (parts.length === 4 && parts[2].startsWith('unique_') && parts[3].startsWith('custom_')) {
1664
+ const device = this.devices.get(parts[2].replace('unique_', ''));
1665
+ if (device && device.deviceName && device.maybeNumber) {
1666
+ const childEndpointName = parts[3].replace('custom_', '');
1667
+ const childEndpoint = device.getChildEndpointByName(childEndpointName);
1668
+ this.log.debug(`Converting unique Matterbridge.EndpointStructure:${key}:${number} to root.parts.Matterbridge.parts.${device.deviceName.replace(/[ .]/g, '')}.parts.${parts[3].replace('custom_', '').replace(/[ .]/g, '')}.__number__:${CYAN}${childEndpoint?.number}${db}`);
1669
+ await nodeStorage
1670
+ .createContext('root')
1671
+ .createContext('parts')
1672
+ .createContext('Matterbridge')
1673
+ .createContext('parts')
1674
+ .createContext(device.deviceName.replace(/[ .]/g, ''))
1675
+ .createContext('parts')
1676
+ .createContext(parts[3].replace('custom_', '').replace(/[ .]/g, ''))
1677
+ .set('__number__', childEndpoint?.number);
1678
+ }
1679
+ }
1680
+ else if (parts.length === 3 && parts[2].startsWith('custom_')) {
1681
+ this.log.debug(`Converting custom Matterbridge.EndpointStructure:${key}:${number} to root.parts.Matterbridge.parts.${parts[2].replace('custom_', '').replace(/[ .]/g, '')}.__number__:${CYAN}${number}${db}`);
1682
+ await nodeStorage.createContext('root').createContext('parts').createContext('Matterbridge').createContext('parts').createContext(parts[2].replace('custom_', '').replace(/[ .]/g, '')).set('__number__', number);
1683
+ }
1684
+ else if (parts.length === 4 && parts[2].startsWith('custom_') && parts[3].startsWith('custom_')) {
1685
+ this.log.debug(`Converting custom Matterbridge.EndpointStructure:${key}:${number} to root.parts.Matterbridge.parts.${parts[2].replace('custom_', '').replace(/[ .]/g, '')}.parts.${parts[3].replace('custom_', '').replace(/[ .]/g, '')}.__number__:${CYAN}${number}${db}`);
1686
+ await nodeStorage
1687
+ .createContext('root')
1688
+ .createContext('parts')
1689
+ .createContext('Matterbridge')
1690
+ .createContext('parts')
1691
+ .createContext(parts[2].replace('custom_', '').replace(/[ .]/g, ''))
1692
+ .createContext('parts')
1693
+ .createContext(parts[3].replace('custom_', '').replace(/[ .]/g, ''))
1694
+ .set('__number__', number);
1695
+ }
1696
+ }
1697
+ await nodeStorage.createContext('persist').set('converted', true);
1698
+ await nodeStorage.createContext('persist').set('deviceName', await context.get('deviceName'));
1699
+ await nodeStorage.createContext('persist').set('deviceType', await context.get('deviceType'));
1700
+ await nodeStorage.createContext('persist').set('vendorId', await context.get('vendorId'));
1701
+ await nodeStorage.createContext('persist').set('vendorName', await context.get('vendorName'));
1702
+ await nodeStorage.createContext('persist').set('productId', await context.get('productId'));
1703
+ await nodeStorage.createContext('persist').set('productName', await context.get('productName'));
1704
+ await nodeStorage.createContext('persist').set('nodeLabel', await context.get('nodeLabel'));
1705
+ await nodeStorage.createContext('persist').set('productLabel', await context.get('productLabel'));
1706
+ await nodeStorage.createContext('persist').set('serialNumber', 'SN' + (await context.get('serialNumber')));
1707
+ await nodeStorage.createContext('persist').set('uniqueId', await context.get('uniqueId'));
1708
+ await nodeStorage.createContext('persist').set('softwareVersion', await context.get('softwareVersion'));
1709
+ await nodeStorage.createContext('persist').set('softwareVersionString', await context.get('softwareVersionString'));
1710
+ await nodeStorage.createContext('persist').set('hardwareVersion', await context.get('hardwareVersion'));
1711
+ await nodeStorage.createContext('persist').set('hardwareVersionString', await context.get('hardwareVersionString'));
1712
+ await context.set('converted', true);
1713
+ this.log.notice(`Matter storage converted to Matterbridge edge for ${plg}${pluginName}${nt}`);
1714
+ this.log.notice(`If you want to try out matterbridge edge (beta) add -edge to the command line.`);
1715
+ }
1716
+ catch (error) {
1717
+ this.log.error(`convertStorage error converting matter storage to Matterbridge edge for ${plg}${pluginName}${er}:`, error);
1718
+ }
1856
1719
  }
1857
- /**
1858
- * Makes a backup copy of the specified matter JSON storage file.
1859
- *
1860
- * @param storageName - The name of the JSON storage file to be backed up.
1861
- * @param backupName - The name of the backup file to be created.
1862
- */
1863
1720
  async backupMatterStorage(storageName, backupName) {
1864
1721
  try {
1865
1722
  this.log.debug(`Making backup copy of ${storageName}`);
@@ -1880,12 +1737,6 @@ export class Matterbridge extends EventEmitter {
1880
1737
  }
1881
1738
  }
1882
1739
  }
1883
- /**
1884
- * Restore the specified matter JSON storage file.
1885
- *
1886
- * @param backupName - The name of the backup file to restore from.
1887
- * @param storageName - The name of the JSON storage file to restored.
1888
- */
1889
1740
  async restoreMatterStorage(backupName, storageName) {
1890
1741
  try {
1891
1742
  this.log.notice(`Restoring the backup copy of ${storageName}`);
@@ -1906,10 +1757,6 @@ export class Matterbridge extends EventEmitter {
1906
1757
  }
1907
1758
  }
1908
1759
  }
1909
- /**
1910
- * Stops the matter storage.
1911
- * @returns {Promise<void>} A promise that resolves when the storage is stopped.
1912
- */
1913
1760
  async stopMatterStorage() {
1914
1761
  this.log.debug('Stopping storage');
1915
1762
  await this.storageManager?.close();
@@ -1918,14 +1765,8 @@ export class Matterbridge extends EventEmitter {
1918
1765
  this.matterbridgeContext = undefined;
1919
1766
  this.mattercontrollerContext = undefined;
1920
1767
  }
1921
- /**
1922
- * Creates a Matter server using the provided storage manager and the provided mdnsInterface.
1923
- * @param storageManager The storage manager to be used by the Matter server.
1924
- *
1925
- */
1926
1768
  createMatterServer(storageManager) {
1927
1769
  this.log.debug('Creating matter server');
1928
- // Validate mdnsInterface
1929
1770
  if (this.mdnsInterface) {
1930
1771
  const networkInterfaces = os.networkInterfaces();
1931
1772
  const availableInterfaces = Object.keys(networkInterfaces);
@@ -1941,10 +1782,6 @@ export class Matterbridge extends EventEmitter {
1941
1782
  this.log.debug(`Created matter server with mdnsInterface: ${this.mdnsInterface ?? 'all available interfaces'}`);
1942
1783
  return matterServer;
1943
1784
  }
1944
- /**
1945
- * Starts the Matter server.
1946
- * If the Matter server is not initialized, it logs an error and performs cleanup.
1947
- */
1948
1785
  async startMatterServer() {
1949
1786
  if (!this.matterServer) {
1950
1787
  this.log.error('No matter server initialized');
@@ -1954,11 +1791,7 @@ export class Matterbridge extends EventEmitter {
1954
1791
  this.log.debug('Starting matter server...');
1955
1792
  await this.matterServer.start();
1956
1793
  this.log.debug('Started matter server');
1957
- // this.commissioningServer?.getRootEndpoint() && logEndpoint(this.commissioningServer?.getRootEndpoint());
1958
1794
  }
1959
- /**
1960
- * Stops the Matter server, commissioningServer and commissioningController.
1961
- */
1962
1795
  async stopMatterServer() {
1963
1796
  this.log.debug('Stopping matter commissioningServer');
1964
1797
  await this.commissioningServer?.close();
@@ -1972,35 +1805,23 @@ export class Matterbridge extends EventEmitter {
1972
1805
  this.matterAggregator = undefined;
1973
1806
  this.matterServer = undefined;
1974
1807
  }
1975
- /**
1976
- * Creates a Matter Aggregator.
1977
- * @param {StorageContext} context - The storage context.
1978
- * @returns {Aggregator} - The created Matter Aggregator.
1979
- */
1980
1808
  async createMatterAggregator(context, pluginName) {
1981
1809
  this.log.debug(`Creating matter aggregator for ${plg}${pluginName}${db}`);
1982
1810
  const matterAggregator = new Aggregator();
1983
1811
  return matterAggregator;
1984
1812
  }
1985
- /**
1986
- * Creates a matter commissioning server.
1987
- *
1988
- * @param {StorageContext} context - The storage context.
1989
- * @param {string} pluginName - The name of the commissioning server.
1990
- * @returns {CommissioningServer} The created commissioning server.
1991
- */
1992
1813
  async createCommisioningServer(context, pluginName) {
1993
1814
  this.log.debug(`Creating matter commissioning server for plugin ${plg}${pluginName}${db}`);
1994
1815
  const deviceName = await context.get('deviceName');
1995
1816
  const deviceType = await context.get('deviceType');
1996
1817
  const vendorId = await context.get('vendorId');
1997
- const vendorName = await context.get('vendorName'); // Home app = Manufacturer
1818
+ const vendorName = await context.get('vendorName');
1998
1819
  const productId = await context.get('productId');
1999
- const productName = await context.get('productName'); // Home app = Model
1820
+ const productName = await context.get('productName');
2000
1821
  const serialNumber = await context.get('serialNumber');
2001
1822
  const uniqueId = await context.get('uniqueId');
2002
1823
  const softwareVersion = await context.get('softwareVersion', 1);
2003
- const softwareVersionString = await context.get('softwareVersionString', '1.0.0'); // Home app = Firmware Revision
1824
+ const softwareVersionString = await context.get('softwareVersionString', '1.0.0');
2004
1825
  const hardwareVersion = await context.get('hardwareVersion', 1);
2005
1826
  const hardwareVersionString = await context.get('hardwareVersionString', '1.0.0');
2006
1827
  this.log.debug(`Creating matter commissioning server for plugin ${plg}${pluginName}${db} with deviceName '${deviceName}' deviceType ${deviceType}(0x${deviceType.toString(16).padStart(4, '0')})`);
@@ -2008,7 +1829,6 @@ export class Matterbridge extends EventEmitter {
2008
1829
  this.log.debug(`Creating matter commissioning server for plugin ${plg}${pluginName}${db} with softwareVersion ${softwareVersion} softwareVersionString ${softwareVersionString}`);
2009
1830
  this.log.debug(`Creating matter commissioning server for plugin ${plg}${pluginName}${db} with hardwareVersion ${hardwareVersion} hardwareVersionString ${hardwareVersionString}`);
2010
1831
  this.log.debug(`Creating matter commissioning server for plugin ${plg}${pluginName}${db} with nodeLabel '${productName}' port ${CYAN}${this.port}${db} discriminator ${CYAN}${this.discriminator}${db} passcode ${CYAN}${this.passcode}${db} `);
2011
- // Validate ipv4address
2012
1832
  if (this.ipv4address) {
2013
1833
  const networkInterfaces = os.networkInterfaces();
2014
1834
  const availableAddresses = Object.values(networkInterfaces)
@@ -2023,7 +1843,6 @@ export class Matterbridge extends EventEmitter {
2023
1843
  this.log.info(`Using ipv4address '${this.ipv4address}' for the Matter commissioning server.`);
2024
1844
  }
2025
1845
  }
2026
- // Validate ipv6address
2027
1846
  if (this.ipv6address) {
2028
1847
  const networkInterfaces = os.networkInterfaces();
2029
1848
  const availableAddresses = Object.values(networkInterfaces)
@@ -2054,7 +1873,7 @@ export class Matterbridge extends EventEmitter {
2054
1873
  nodeLabel: productName,
2055
1874
  productLabel: productName,
2056
1875
  softwareVersion,
2057
- softwareVersionString, // Home app = Firmware Revision
1876
+ softwareVersionString,
2058
1877
  hardwareVersion,
2059
1878
  hardwareVersionString,
2060
1879
  uniqueId,
@@ -2150,24 +1969,6 @@ export class Matterbridge extends EventEmitter {
2150
1969
  commissioningServer.addCommandHandler('testEventTrigger', async ({ request: { enableKey, eventTrigger } }) => this.log.info(`testEventTrigger called on GeneralDiagnostic cluster: ${enableKey} ${eventTrigger}`));
2151
1970
  return commissioningServer;
2152
1971
  }
2153
- /**
2154
- * Creates a commissioning server storage context.
2155
- *
2156
- * @param pluginName - The name of the plugin.
2157
- * @param deviceName - The name of the device.
2158
- * @param deviceType - The type of the device.
2159
- * @param vendorId - The vendor ID.
2160
- * @param vendorName - The vendor name.
2161
- * @param productId - The product ID.
2162
- * @param productName - The product name.
2163
- * @param serialNumber - The serial number of the device (optional).
2164
- * @param uniqueId - The unique ID of the device (optional).
2165
- * @param softwareVersion - The software version of the device (optional).
2166
- * @param softwareVersionString - The software version string of the device (optional).
2167
- * @param hardwareVersion - The hardware version of the device (optional).
2168
- * @param hardwareVersionString - The hardware version string of the device (optional).
2169
- * @returns The storage context for the commissioning server.
2170
- */
2171
1972
  async createCommissioningServerContext(pluginName, deviceName, deviceType, vendorId, vendorName, productId, productName) {
2172
1973
  if (!this.storageManager)
2173
1974
  throw new Error('No storage manager initialized');
@@ -2195,13 +1996,6 @@ export class Matterbridge extends EventEmitter {
2195
1996
  this.log.debug(`- hardwareVersion: ${await storageContext.get('hardwareVersion')} hardwareVersionString: ${await storageContext.get('hardwareVersionString')}`);
2196
1997
  return storageContext;
2197
1998
  }
2198
- /**
2199
- * Imports the commissioning server context for a specific plugin and device.
2200
- * @param pluginName - The name of the plugin.
2201
- * @param device - The MatterbridgeDevice object representing the device.
2202
- * @returns The commissioning server context.
2203
- * @throws Error if the BasicInformationCluster is not found.
2204
- */
2205
1999
  async importCommissioningServerContext(pluginName, device) {
2206
2000
  this.log.debug(`Importing matter commissioning server storage context from device for ${plg}${pluginName}${db}`);
2207
2001
  const basic = device.getClusterServer(BasicInformationCluster);
@@ -2236,14 +2030,6 @@ export class Matterbridge extends EventEmitter {
2236
2030
  this.log.debug(`- hardwareVersion: ${await storageContext.get('hardwareVersion')} hardwareVersionString: ${await storageContext.get('hardwareVersionString')}`);
2237
2031
  return storageContext;
2238
2032
  }
2239
- /**
2240
- * Shows the commissioning server QR code for a given plugin.
2241
- * @param {CommissioningServer} commissioningServer - The commissioning server instance.
2242
- * @param {StorageContext} storageContext - The storage context instance.
2243
- * @param {NodeStorage} nodeContext - The node storage instance.
2244
- * @param {string} pluginName - The name of the plugin of Matterbridge in bridge mode.
2245
- * @returns {Promise<void>} - A promise that resolves when the QR code is shown.
2246
- */
2247
2033
  async showCommissioningQRCode(commissioningServer, storageContext, nodeContext, pluginName) {
2248
2034
  if (!commissioningServer || !storageContext || !nodeContext || !pluginName) {
2249
2035
  this.log.error(`showCommissioningQRCode error: commissioningServer: ${!commissioningServer} storageContext: ${!storageContext} nodeContext: ${!nodeContext} pluginName: ${pluginName}`);
@@ -2254,8 +2040,7 @@ export class Matterbridge extends EventEmitter {
2254
2040
  const { qrPairingCode, manualPairingCode } = commissioningServer.getPairingCode();
2255
2041
  const QrCode = new QrCodeSchema();
2256
2042
  this.log.info(`*The commissioning server on port ${commissioningServer.getPort()} for ${plg}${pluginName}${nf} is not commissioned. Pair it scanning the QR code:\n\n`);
2257
- // eslint-disable-next-line no-console
2258
- if (this.log.logLevel === "debug" /* LogLevel.DEBUG */ || this.log.logLevel === "info" /* LogLevel.INFO */)
2043
+ if (this.log.logLevel === "debug" || this.log.logLevel === "info")
2259
2044
  console.log(`${QrCode.encode(qrPairingCode)}\n`);
2260
2045
  this.log.info(`${plg}${pluginName}${nf} \n\nqrPairingCode: ${qrPairingCode} \n\nManual pairing code: ${manualPairingCode}\n`);
2261
2046
  if (pluginName === 'Matterbridge') {
@@ -2302,12 +2087,6 @@ export class Matterbridge extends EventEmitter {
2302
2087
  }
2303
2088
  this.wssSendRefreshRequired();
2304
2089
  }
2305
- /**
2306
- * Sanitizes the fabric information by converting bigint properties to string cause res.json doesn't know bigint.
2307
- *
2308
- * @param fabricInfo - The array of exposed fabric information objects.
2309
- * @returns An array of sanitized exposed fabric information objects.
2310
- */
2311
2090
  sanitizeFabricInformations(fabricInfo) {
2312
2091
  return fabricInfo.map((info) => {
2313
2092
  return {
@@ -2321,12 +2100,6 @@ export class Matterbridge extends EventEmitter {
2321
2100
  };
2322
2101
  });
2323
2102
  }
2324
- /**
2325
- * Sanitizes the session information by converting bigint properties to string.
2326
- *
2327
- * @param sessionInfo - The array of session information objects.
2328
- * @returns An array of sanitized session information objects.
2329
- */
2330
2103
  sanitizeSessionInformation(sessionInfo) {
2331
2104
  return sessionInfo
2332
2105
  .filter((session) => session.isPeerActive)
@@ -2354,12 +2127,6 @@ export class Matterbridge extends EventEmitter {
2354
2127
  };
2355
2128
  });
2356
2129
  }
2357
- /**
2358
- * Sets the reachability of a commissioning server and trigger.
2359
- *
2360
- * @param {CommissioningServer} commissioningServer - The commissioning server to set the reachability for.
2361
- * @param {boolean} reachable - The new reachability status.
2362
- */
2363
2130
  setCommissioningServerReachability(commissioningServer, reachable) {
2364
2131
  const basicInformationCluster = commissioningServer?.getRootClusterServer(BasicInformationCluster);
2365
2132
  if (basicInformationCluster && basicInformationCluster.attributes.reachable !== undefined)
@@ -2367,11 +2134,6 @@ export class Matterbridge extends EventEmitter {
2367
2134
  if (basicInformationCluster && basicInformationCluster.triggerReachableChangedEvent)
2368
2135
  basicInformationCluster.triggerReachableChangedEvent({ reachableNewValue: reachable });
2369
2136
  }
2370
- /**
2371
- * Sets the reachability of the specified matter aggregator and its bridged devices and trigger.
2372
- * @param {Aggregator} matterAggregator - The matter aggregator to set the reachability for.
2373
- * @param {boolean} reachable - A boolean indicating the reachability status to set.
2374
- */
2375
2137
  setAggregatorReachability(matterAggregator, reachable) {
2376
2138
  const basicInformationCluster = matterAggregator.getClusterServer(BasicInformationCluster);
2377
2139
  if (basicInformationCluster && basicInformationCluster.attributes.reachable !== undefined)
@@ -2384,12 +2146,6 @@ export class Matterbridge extends EventEmitter {
2384
2146
  device.getClusterServer(BridgedDeviceBasicInformationCluster)?.triggerReachableChangedEvent({ reachableNewValue: reachable });
2385
2147
  });
2386
2148
  }
2387
- /**
2388
- * Sets the reachability of a device and trigger.
2389
- *
2390
- * @param {MatterbridgeDevice} device - The device to set the reachability for.
2391
- * @param {boolean} reachable - The new reachability status of the device.
2392
- */
2393
2149
  setDeviceReachability(device, reachable) {
2394
2150
  const basicInformationCluster = device.getClusterServer(BasicInformationCluster);
2395
2151
  if (basicInformationCluster && basicInformationCluster.attributes.reachable !== undefined)
@@ -2438,10 +2194,6 @@ export class Matterbridge extends EventEmitter {
2438
2194
  }
2439
2195
  return vendorName;
2440
2196
  };
2441
- /**
2442
- * Retrieves the base registered plugins sanitized for res.json().
2443
- * @returns {BaseRegisteredPlugin[]} A promise that resolves to an array of BaseRegisteredPlugin objects.
2444
- */
2445
2197
  async getBaseRegisteredPlugins() {
2446
2198
  const baseRegisteredPlugins = [];
2447
2199
  for (const plugin of this.plugins) {
@@ -2473,36 +2225,13 @@ export class Matterbridge extends EventEmitter {
2473
2225
  }
2474
2226
  return baseRegisteredPlugins;
2475
2227
  }
2476
- /**
2477
- * Spawns a child process with the given command and arguments.
2478
- * @param {string} command - The command to execute.
2479
- * @param {string[]} args - The arguments to pass to the command (default: []).
2480
- * @returns {Promise<boolean>} A promise that resolves when the child process exits successfully, or rejects if there is an error.
2481
- */
2482
2228
  async spawnCommand(command, args = []) {
2483
- /*
2484
- npm > npm.cmd on windows
2485
- cmd.exe ['dir'] on windows
2486
- await this.spawnCommand('npm', ['install', '-g', 'matterbridge']);
2487
- process.on('unhandledRejection', (reason, promise) => {
2488
- this.log.error('Unhandled Rejection at:', promise, 'reason:', reason);
2489
- });
2490
-
2491
- spawn - [14:27:21.125] [Matterbridge:spawn]: changed 38 packages in 4s
2492
- spawn - [14:27:21.125] [Matterbridge:spawn]: 10 packages are looking for funding run `npm fund` for details
2493
- debug - [14:27:21.131] [Matterbridge]: Child process exited with code 0 and signal null
2494
- debug - [14:27:21.131] [Matterbridge]: Child process stdio streams have closed with code 0
2495
- */
2496
2229
  const cmdLine = command + ' ' + args.join(' ');
2497
2230
  if (process.platform === 'win32' && command === 'npm') {
2498
- // Must be spawn('cmd.exe', ['/c', 'npm -g install <package>']);
2499
2231
  const argstring = 'npm ' + args.join(' ');
2500
2232
  args.splice(0, args.length, '/c', argstring);
2501
2233
  command = 'cmd.exe';
2502
2234
  }
2503
- // Decide when using sudo on linux
2504
- // When you need sudo: Spawn stderr: npm error Error: EACCES: permission denied
2505
- // When you don't need sudo: Failed to start child process "npm install -g matterbridge-eve-door": spawn sudo ENOENT
2506
2235
  if (hasParameter('sudo') || (process.platform === 'linux' && command === 'npm' && !hasParameter('docker') && !hasParameter('nosudo'))) {
2507
2236
  args.unshift(command);
2508
2237
  command = 'sudo';
@@ -2560,102 +2289,55 @@ export class Matterbridge extends EventEmitter {
2560
2289
  }
2561
2290
  });
2562
2291
  }
2563
- /**
2564
- * Sends a WebSocket message to all connected clients.
2565
- *
2566
- * @param {string} level - The logger level of the message: debug info notice warn error fatal...
2567
- * @param {string} time - The time string of the message
2568
- * @param {string} name - The logger name of the message
2569
- * @param {string} message - The content of the message.
2570
- */
2571
2292
  wssSendMessage(level, time, name, message) {
2572
2293
  if (!level || !time || !name || !message)
2573
2294
  return;
2574
- // Remove ANSI escape codes from the message
2575
- // eslint-disable-next-line no-control-regex
2576
2295
  message = message.replace(/\x1B\[[0-9;]*[m|s|u|K]/g, '');
2577
- // Remove leading asterisks from the message
2578
2296
  message = message.replace(/^\*+/, '');
2579
- // Replace all occurrences of \t and \n
2580
2297
  message = message.replace(/[\t\n]/g, '');
2581
- // Remove non-printable characters
2582
- // eslint-disable-next-line no-control-regex
2583
2298
  message = message.replace(/[\x00-\x1F\x7F]/g, '');
2584
- // Replace all occurrences of \" with "
2585
2299
  message = message.replace(/\\"/g, '"');
2586
- // Define the maximum allowed length for continuous characters without a space
2587
2300
  const maxContinuousLength = 100;
2588
2301
  const keepStartLength = 20;
2589
2302
  const keepEndLength = 20;
2590
- // Split the message into words
2591
2303
  message = message
2592
2304
  .split(' ')
2593
2305
  .map((word) => {
2594
- // If the word length exceeds the max continuous length, insert spaces and truncate
2595
2306
  if (word.length > maxContinuousLength) {
2596
2307
  return word.slice(0, keepStartLength) + ' ... ' + word.slice(-keepEndLength);
2597
2308
  }
2598
2309
  return word;
2599
2310
  })
2600
2311
  .join(' ');
2601
- // Send the message to all connected clients
2602
2312
  this.webSocketServer?.clients.forEach((client) => {
2603
2313
  if (client.readyState === WebSocket.OPEN) {
2604
2314
  client.send(JSON.stringify({ id: WS_ID_LOG, src: 'Matterbridge', level, time, name, message }));
2605
2315
  }
2606
2316
  });
2607
2317
  }
2608
- /**
2609
- * Sends a need to refresh WebSocket message to all connected clients.
2610
- *
2611
- */
2612
2318
  wssSendRefreshRequired() {
2613
2319
  this.matterbridgeInformation.refreshRequired = true;
2614
- // Send the message to all connected clients
2615
2320
  this.webSocketServer?.clients.forEach((client) => {
2616
2321
  if (client.readyState === WebSocket.OPEN) {
2617
2322
  client.send(JSON.stringify({ id: WS_ID_REFRESH_NEEDED, src: 'Matterbridge', dst: 'Matterbridge', method: 'refresh_required', params: {} }));
2618
2323
  }
2619
2324
  });
2620
2325
  }
2621
- /**
2622
- * Sends a need to restart WebSocket message to all connected clients.
2623
- *
2624
- */
2625
2326
  wssSendRestartRequired() {
2626
2327
  this.matterbridgeInformation.restartRequired = true;
2627
- // Send the message to all connected clients
2628
2328
  this.webSocketServer?.clients.forEach((client) => {
2629
2329
  if (client.readyState === WebSocket.OPEN) {
2630
2330
  client.send(JSON.stringify({ id: WS_ID_RESTART_NEEDED, src: 'Matterbridge', dst: 'Matterbridge', method: 'restart_required', params: {} }));
2631
2331
  }
2632
2332
  });
2633
2333
  }
2634
- /**
2635
- * Initializes the frontend of Matterbridge.
2636
- *
2637
- * @param port The port number to run the frontend server on. Default is 8283.
2638
- */
2639
2334
  async initializeFrontend(port = 8283) {
2640
2335
  let initializeError = false;
2641
2336
  this.log.debug(`Initializing the frontend ${hasParameter('ssl') ? 'https' : 'http'} server on port ${YELLOW}${port}${db}`);
2642
- // Create the express app that serves the frontend
2643
2337
  this.expressApp = express();
2644
- // Log all requests to the server for debugging
2645
- /*
2646
- if (hasParameter('homedir')) {
2647
- this.expressApp.use((req, res, next) => {
2648
- this.log.debug(`Received request on expressApp: ${req.method} ${req.url}`);
2649
- next();
2650
- });
2651
- }
2652
- */
2653
- // Serve static files from '/static' endpoint
2654
2338
  this.expressApp.use(express.static(path.join(this.rootDirectory, 'frontend/build')));
2655
2339
  if (!hasParameter('ssl')) {
2656
- // Create an HTTP server and attach the express app
2657
2340
  this.httpServer = createServer(this.expressApp);
2658
- // Listen on the specified port
2659
2341
  if (hasParameter('ingress')) {
2660
2342
  this.httpServer.listen(port, '0.0.0.0', () => {
2661
2343
  this.log.info(`The frontend http server is listening on ${UNDERLINE}http://0.0.0.0:${port}${UNDERLINEOFF}${rs}`);
@@ -2669,7 +2351,6 @@ export class Matterbridge extends EventEmitter {
2669
2351
  this.log.info(`The frontend http server is listening on ${UNDERLINE}http://[${this.systemInformation.ipv6Address}]:${port}${UNDERLINEOFF}${rs}`);
2670
2352
  });
2671
2353
  }
2672
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
2673
2354
  this.httpServer.on('error', (error) => {
2674
2355
  this.log.error(`Frontend http server error listening on ${port}`);
2675
2356
  switch (error.code) {
@@ -2685,7 +2366,6 @@ export class Matterbridge extends EventEmitter {
2685
2366
  });
2686
2367
  }
2687
2368
  else {
2688
- // Load the SSL certificate, the private key and optionally the CA certificate
2689
2369
  let cert;
2690
2370
  try {
2691
2371
  cert = await fs.readFile(path.join(this.matterbridgeDirectory, 'certs/cert.pem'), 'utf8');
@@ -2713,9 +2393,7 @@ export class Matterbridge extends EventEmitter {
2713
2393
  this.log.info(`CA certificate file ${path.join(this.matterbridgeDirectory, 'certs/ca.pem')} not loaded: ${error}`);
2714
2394
  }
2715
2395
  const serverOptions = { cert, key, ca };
2716
- // Create an HTTPS server with the SSL certificate and private key (ca is optional) and attach the express app
2717
2396
  this.httpsServer = https.createServer(serverOptions, this.expressApp);
2718
- // Listen on the specified port
2719
2397
  if (hasParameter('ingress')) {
2720
2398
  this.httpsServer.listen(port, '0.0.0.0', () => {
2721
2399
  this.log.info(`The frontend https server is listening on ${UNDERLINE}https://0.0.0.0:${port}${UNDERLINEOFF}${rs}`);
@@ -2729,7 +2407,6 @@ export class Matterbridge extends EventEmitter {
2729
2407
  this.log.info(`The frontend https server is listening on ${UNDERLINE}https://[${this.systemInformation.ipv6Address}]:${port}${UNDERLINEOFF}${rs}`);
2730
2408
  });
2731
2409
  }
2732
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
2733
2410
  this.httpsServer.on('error', (error) => {
2734
2411
  this.log.error(`Frontend https server error listening on ${port}`);
2735
2412
  switch (error.code) {
@@ -2746,13 +2423,12 @@ export class Matterbridge extends EventEmitter {
2746
2423
  }
2747
2424
  if (initializeError)
2748
2425
  return;
2749
- // Createe a WebSocket server and attach it to the http or https server
2750
2426
  const wssPort = port;
2751
2427
  const wssHost = hasParameter('ssl') ? `wss://${this.systemInformation.ipv4Address}:${wssPort}` : `ws://${this.systemInformation.ipv4Address}:${wssPort}`;
2752
2428
  this.webSocketServer = new WebSocketServer(hasParameter('ssl') ? { server: this.httpsServer } : { server: this.httpServer });
2753
2429
  this.webSocketServer.on('connection', (ws, request) => {
2754
2430
  const clientIp = request.socket.remoteAddress;
2755
- AnsiLogger.setGlobalCallback(this.wssSendMessage.bind(this), "debug" /* LogLevel.DEBUG */);
2431
+ AnsiLogger.setGlobalCallback(this.wssSendMessage.bind(this), "debug");
2756
2432
  this.log.info(`WebSocketServer client "${clientIp}" connected to Matterbridge`);
2757
2433
  ws.on('message', (message) => {
2758
2434
  this.log.debug(`WebSocket client message: ${message}`);
@@ -2785,7 +2461,6 @@ export class Matterbridge extends EventEmitter {
2785
2461
  this.webSocketServer.on('error', (ws, error) => {
2786
2462
  this.log.error(`WebSocketServer error: ${error}`);
2787
2463
  });
2788
- // Endpoint to validate login code
2789
2464
  this.expressApp.post('/api/login', express.json(), async (req, res) => {
2790
2465
  const { password } = req.body;
2791
2466
  this.log.debug('The frontend sent /api/login', password);
@@ -2804,14 +2479,12 @@ export class Matterbridge extends EventEmitter {
2804
2479
  this.log.warn('/api/login error wrong password');
2805
2480
  res.json({ valid: false });
2806
2481
  }
2807
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
2808
2482
  }
2809
2483
  catch (error) {
2810
2484
  this.log.error('/api/login error getting password');
2811
2485
  res.json({ valid: false });
2812
2486
  }
2813
2487
  });
2814
- // Endpoint to provide settings
2815
2488
  this.expressApp.get('/api/settings', express.json(), async (req, res) => {
2816
2489
  this.log.debug('The frontend sent /api/settings');
2817
2490
  this.matterbridgeInformation.bridgeMode = this.bridgeMode;
@@ -2832,17 +2505,13 @@ export class Matterbridge extends EventEmitter {
2832
2505
  this.matterbridgeInformation.matterbridgeSessionInformations = Array.from(this.matterbridgeSessionInformations.values());
2833
2506
  this.matterbridgeInformation.profile = this.profile;
2834
2507
  const response = { wssHost, ssl: hasParameter('ssl'), systemInformation: this.systemInformation, matterbridgeInformation: this.matterbridgeInformation };
2835
- // this.log.debug('Response:', debugStringify(response));
2836
2508
  res.json(response);
2837
2509
  });
2838
- // Endpoint to provide plugins
2839
2510
  this.expressApp.get('/api/plugins', async (req, res) => {
2840
2511
  this.log.debug('The frontend sent /api/plugins');
2841
2512
  const response = await this.getBaseRegisteredPlugins();
2842
- // this.log.debug('Response:', debugStringify(response));
2843
2513
  res.json(response);
2844
2514
  });
2845
- // Endpoint to provide devices
2846
2515
  this.expressApp.get('/api/devices', (req, res) => {
2847
2516
  this.log.debug('The frontend sent /api/devices');
2848
2517
  const devices = [];
@@ -2875,10 +2544,8 @@ export class Matterbridge extends EventEmitter {
2875
2544
  cluster: cluster,
2876
2545
  });
2877
2546
  });
2878
- // this.log.debug('Response:', debugStringify(data));
2879
2547
  res.json(devices);
2880
2548
  });
2881
- // Endpoint to provide the cluster servers of the devices
2882
2549
  this.expressApp.get('/api/devices_clusters/:selectedPluginName/:selectedDeviceEndpoint', (req, res) => {
2883
2550
  const selectedPluginName = req.params.selectedPluginName;
2884
2551
  const selectedDeviceEndpoint = parseInt(req.params.selectedDeviceEndpoint, 10);
@@ -2898,7 +2565,6 @@ export class Matterbridge extends EventEmitter {
2898
2565
  Object.entries(clusterServer.attributes).forEach(([key, value]) => {
2899
2566
  if (clusterServer.name === 'EveHistory')
2900
2567
  return;
2901
- // this.log.debug(`***--clusterServer: ${clusterServer.name}(${clusterServer.id}) attribute:${key}(${value.id}) ${value.isFixed} ${value.isWritable} ${value.isWritable}`);
2902
2568
  let attributeValue;
2903
2569
  try {
2904
2570
  if (typeof value.getLocal() === 'object')
@@ -2909,7 +2575,6 @@ export class Matterbridge extends EventEmitter {
2909
2575
  catch (error) {
2910
2576
  attributeValue = 'Fabric-Scoped';
2911
2577
  this.log.debug(`GetLocal value ${error} in clusterServer: ${clusterServer.name}(${clusterServer.id}) attribute: ${key}(${value.id})`);
2912
- // console.log(error);
2913
2578
  }
2914
2579
  data.push({
2915
2580
  endpoint: device.number ? device.number.toString() : '...',
@@ -2922,14 +2587,12 @@ export class Matterbridge extends EventEmitter {
2922
2587
  });
2923
2588
  });
2924
2589
  device.getChildEndpoints().forEach((childEndpoint) => {
2925
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
2926
2590
  const name = this.edge ? childEndpoint.endpoint?.id : childEndpoint.uniqueStorageKey;
2927
2591
  const clusterServers = childEndpoint.getAllClusterServers();
2928
2592
  clusterServers.forEach((clusterServer) => {
2929
2593
  Object.entries(clusterServer.attributes).forEach(([key, value]) => {
2930
2594
  if (clusterServer.name === 'EveHistory')
2931
2595
  return;
2932
- // this.log.debug(`***--clusterServer: ${clusterServer.name}(${clusterServer.id}) attribute:${key}(${value.id}) ${value.isFixed} ${value.isWritable} ${value.isWritable}`);
2933
2596
  let attributeValue;
2934
2597
  try {
2935
2598
  if (typeof value.getLocal() === 'object')
@@ -2940,7 +2603,6 @@ export class Matterbridge extends EventEmitter {
2940
2603
  catch (error) {
2941
2604
  attributeValue = 'Unavailable';
2942
2605
  this.log.debug(`GetLocal error ${error} in clusterServer: ${clusterServer.name}(${clusterServer.id}) attribute: ${key}(${value.id})`);
2943
- // console.log(error);
2944
2606
  }
2945
2607
  data.push({
2946
2608
  endpoint: (childEndpoint.number ? childEndpoint.number.toString() : '...') + (name ? ' (' + name + ')' : ''),
@@ -2957,7 +2619,6 @@ export class Matterbridge extends EventEmitter {
2957
2619
  });
2958
2620
  res.json(data);
2959
2621
  });
2960
- // Endpoint to view the log
2961
2622
  this.expressApp.get('/api/view-log', async (req, res) => {
2962
2623
  this.log.debug('The frontend sent /api/log');
2963
2624
  try {
@@ -2970,12 +2631,10 @@ export class Matterbridge extends EventEmitter {
2970
2631
  res.status(500).send('Error reading log file');
2971
2632
  }
2972
2633
  });
2973
- // Endpoint to download the matterbridge log
2974
2634
  this.expressApp.get('/api/download-mblog', async (req, res) => {
2975
2635
  this.log.debug('The frontend sent /api/download-mblog');
2976
2636
  try {
2977
2637
  await fs.access(path.join(this.matterbridgeDirectory, this.matterbrideLoggerFile), fs.constants.F_OK);
2978
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
2979
2638
  }
2980
2639
  catch (error) {
2981
2640
  fs.appendFile(path.join(this.matterbridgeDirectory, this.matterbrideLoggerFile), 'Enable the log on file in the settings to enable the file logger');
@@ -2987,12 +2646,10 @@ export class Matterbridge extends EventEmitter {
2987
2646
  }
2988
2647
  });
2989
2648
  });
2990
- // Endpoint to download the matter log
2991
2649
  this.expressApp.get('/api/download-mjlog', async (req, res) => {
2992
2650
  this.log.debug('The frontend sent /api/download-mjlog');
2993
2651
  try {
2994
2652
  await fs.access(path.join(this.matterbridgeDirectory, this.matterLoggerFile), fs.constants.F_OK);
2995
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
2996
2653
  }
2997
2654
  catch (error) {
2998
2655
  fs.appendFile(path.join(this.matterbridgeDirectory, this.matterLoggerFile), 'Enable the log on file in the settings to enable the file logger');
@@ -3004,7 +2661,6 @@ export class Matterbridge extends EventEmitter {
3004
2661
  }
3005
2662
  });
3006
2663
  });
3007
- // Endpoint to download the matter storage file
3008
2664
  this.expressApp.get('/api/download-mjstorage', (req, res) => {
3009
2665
  this.log.debug('The frontend sent /api/download-mjstorage');
3010
2666
  res.download(path.join(this.matterbridgeDirectory, this.matterStorageName), 'matterbridge.json', (error) => {
@@ -3014,7 +2670,6 @@ export class Matterbridge extends EventEmitter {
3014
2670
  }
3015
2671
  });
3016
2672
  });
3017
- // Endpoint to download the matterbridge storage directory
3018
2673
  this.expressApp.get('/api/download-mbstorage', async (req, res) => {
3019
2674
  this.log.debug('The frontend sent /api/download-mbstorage');
3020
2675
  await createZip(path.join(os.tmpdir(), `matterbridge.${this.nodeStorageName}.zip`), path.join(this.matterbridgeDirectory, this.nodeStorageName));
@@ -3025,7 +2680,6 @@ export class Matterbridge extends EventEmitter {
3025
2680
  }
3026
2681
  });
3027
2682
  });
3028
- // Endpoint to download the matterbridge plugin directory
3029
2683
  this.expressApp.get('/api/download-pluginstorage', async (req, res) => {
3030
2684
  this.log.debug('The frontend sent /api/download-pluginstorage');
3031
2685
  await createZip(path.join(os.tmpdir(), `matterbridge.pluginstorage.zip`), this.matterbridgePluginDirectory);
@@ -3036,11 +2690,9 @@ export class Matterbridge extends EventEmitter {
3036
2690
  }
3037
2691
  });
3038
2692
  });
3039
- // Endpoint to download the matterbridge plugin config files
3040
2693
  this.expressApp.get('/api/download-pluginconfig', async (req, res) => {
3041
2694
  this.log.debug('The frontend sent /api/download-pluginconfig');
3042
2695
  await createZip(path.join(os.tmpdir(), `matterbridge.pluginconfig.zip`), path.relative(process.cwd(), path.join(this.matterbridgeDirectory, '*.config.json')));
3043
- // await createZip(path.join(os.tmpdir(), `matterbridge.pluginconfig.zip`), path.relative(process.cwd(), path.join(this.matterbridgeDirectory, 'certs', '*.*')), path.relative(process.cwd(), path.join(this.matterbridgeDirectory, '*.config.json')));
3044
2696
  res.download(path.join(os.tmpdir(), `matterbridge.pluginconfig.zip`), `matterbridge.pluginconfig.zip`, (error) => {
3045
2697
  if (error) {
3046
2698
  this.log.error(`Error downloading file matterbridge.pluginstorage.zip: ${error instanceof Error ? error.message : error}`);
@@ -3048,7 +2700,6 @@ export class Matterbridge extends EventEmitter {
3048
2700
  }
3049
2701
  });
3050
2702
  });
3051
- // Endpoint to download the matterbridge plugin config files
3052
2703
  this.expressApp.get('/api/download-backup', async (req, res) => {
3053
2704
  this.log.debug('The frontend sent /api/download-backup');
3054
2705
  res.download(path.join(os.tmpdir(), `matterbridge.backup.zip`), `matterbridge.backup.zip`, (error) => {
@@ -3058,7 +2709,6 @@ export class Matterbridge extends EventEmitter {
3058
2709
  }
3059
2710
  });
3060
2711
  });
3061
- // Endpoint to receive commands
3062
2712
  this.expressApp.post('/api/command/:command/:param', express.json(), async (req, res) => {
3063
2713
  const command = req.params.command;
3064
2714
  let param = req.params.param;
@@ -3068,15 +2718,13 @@ export class Matterbridge extends EventEmitter {
3068
2718
  return;
3069
2719
  }
3070
2720
  this.log.debug(`Received frontend command: ${command}:${param}`);
3071
- // Handle the command setpassword from Settings
3072
2721
  if (command === 'setpassword') {
3073
- const password = param.slice(1, -1); // Remove the first and last characters
2722
+ const password = param.slice(1, -1);
3074
2723
  this.log.debug('setpassword', param, password);
3075
2724
  await this.nodeContext?.set('password', password);
3076
2725
  res.json({ message: 'Command received' });
3077
2726
  return;
3078
2727
  }
3079
- // Handle the command setbridgemode from Settings
3080
2728
  if (command === 'setbridgemode') {
3081
2729
  this.log.debug(`setbridgemode: ${param}`);
3082
2730
  this.wssSendRestartRequired();
@@ -3084,7 +2732,6 @@ export class Matterbridge extends EventEmitter {
3084
2732
  res.json({ message: 'Command received' });
3085
2733
  return;
3086
2734
  }
3087
- // Handle the command backup from Settings
3088
2735
  if (command === 'backup') {
3089
2736
  this.log.notice(`Prepairing the backup...`);
3090
2737
  await createZip(path.join(os.tmpdir(), `matterbridge.backup.zip`), path.join(this.matterbridgeDirectory), path.join(this.matterbridgePluginDirectory));
@@ -3092,26 +2739,25 @@ export class Matterbridge extends EventEmitter {
3092
2739
  res.json({ message: 'Command received' });
3093
2740
  return;
3094
2741
  }
3095
- // Handle the command setmbloglevel from Settings
3096
2742
  if (command === 'setmbloglevel') {
3097
2743
  this.log.debug('Matterbridge log level:', param);
3098
2744
  if (param === 'Debug') {
3099
- this.log.logLevel = "debug" /* LogLevel.DEBUG */;
2745
+ this.log.logLevel = "debug";
3100
2746
  }
3101
2747
  else if (param === 'Info') {
3102
- this.log.logLevel = "info" /* LogLevel.INFO */;
2748
+ this.log.logLevel = "info";
3103
2749
  }
3104
2750
  else if (param === 'Notice') {
3105
- this.log.logLevel = "notice" /* LogLevel.NOTICE */;
2751
+ this.log.logLevel = "notice";
3106
2752
  }
3107
2753
  else if (param === 'Warn') {
3108
- this.log.logLevel = "warn" /* LogLevel.WARN */;
2754
+ this.log.logLevel = "warn";
3109
2755
  }
3110
2756
  else if (param === 'Error') {
3111
- this.log.logLevel = "error" /* LogLevel.ERROR */;
2757
+ this.log.logLevel = "error";
3112
2758
  }
3113
2759
  else if (param === 'Fatal') {
3114
- this.log.logLevel = "fatal" /* LogLevel.FATAL */;
2760
+ this.log.logLevel = "fatal";
3115
2761
  }
3116
2762
  await this.nodeContext?.set('matterbridgeLogLevel', this.log.logLevel);
3117
2763
  MatterbridgeDevice.logLevel = this.log.logLevel;
@@ -3119,13 +2765,12 @@ export class Matterbridge extends EventEmitter {
3119
2765
  for (const plugin of this.plugins) {
3120
2766
  if (!plugin.platform || !plugin.platform.config)
3121
2767
  continue;
3122
- plugin.platform.log.logLevel = plugin.platform.config.debug ? "debug" /* LogLevel.DEBUG */ : this.log.logLevel;
3123
- await plugin.platform.onChangeLoggerLevel(plugin.platform.config.debug ? "debug" /* LogLevel.DEBUG */ : this.log.logLevel);
2768
+ plugin.platform.log.logLevel = plugin.platform.config.debug ? "debug" : this.log.logLevel;
2769
+ await plugin.platform.onChangeLoggerLevel(plugin.platform.config.debug ? "debug" : this.log.logLevel);
3124
2770
  }
3125
2771
  res.json({ message: 'Command received' });
3126
2772
  return;
3127
2773
  }
3128
- // Handle the command setmbloglevel from Settings
3129
2774
  if (command === 'setmjloglevel') {
3130
2775
  this.log.debug('Matter.js log level:', param);
3131
2776
  if (param === 'Debug') {
@@ -3150,34 +2795,30 @@ export class Matterbridge extends EventEmitter {
3150
2795
  res.json({ message: 'Command received' });
3151
2796
  return;
3152
2797
  }
3153
- // Handle the command setmdnsinterface from Settings
3154
2798
  if (command === 'setmdnsinterface') {
3155
- param = param.slice(1, -1); // Remove the first and last characters *mdns*
2799
+ param = param.slice(1, -1);
3156
2800
  this.matterbridgeInformation.mattermdnsinterface = param;
3157
2801
  this.log.debug('Matter.js mdns interface:', param === '' ? 'All interfaces' : param);
3158
2802
  await this.nodeContext?.set('mattermdnsinterface', param);
3159
2803
  res.json({ message: 'Command received' });
3160
2804
  return;
3161
2805
  }
3162
- // Handle the command setipv4address from Settings
3163
2806
  if (command === 'setipv4address') {
3164
- param = param.slice(1, -1); // Remove the first and last characters *ip*
2807
+ param = param.slice(1, -1);
3165
2808
  this.matterbridgeInformation.matteripv4address = param;
3166
2809
  this.log.debug('Matter.js ipv4 address:', param === '' ? 'All ipv4 addresses' : param);
3167
2810
  await this.nodeContext?.set('matteripv4address', param);
3168
2811
  res.json({ message: 'Command received' });
3169
2812
  return;
3170
2813
  }
3171
- // Handle the command setipv6address from Settings
3172
2814
  if (command === 'setipv6address') {
3173
- param = param.slice(1, -1); // Remove the first and last characters *ip*
2815
+ param = param.slice(1, -1);
3174
2816
  this.matterbridgeInformation.matteripv6address = param;
3175
2817
  this.log.debug('Matter.js ipv6 address:', param === '' ? 'All ipv6 addresses' : param);
3176
2818
  await this.nodeContext?.set('matteripv6address', param);
3177
2819
  res.json({ message: 'Command received' });
3178
2820
  return;
3179
2821
  }
3180
- // Handle the command setmatterport from Settings
3181
2822
  if (command === 'setmatterport') {
3182
2823
  const port = Math.min(Math.max(parseInt(param), 5540), 5560);
3183
2824
  this.matterbridgeInformation.matterPort = port;
@@ -3186,7 +2827,6 @@ export class Matterbridge extends EventEmitter {
3186
2827
  res.json({ message: 'Command received' });
3187
2828
  return;
3188
2829
  }
3189
- // Handle the command setmatterdiscriminator from Settings
3190
2830
  if (command === 'setmatterdiscriminator') {
3191
2831
  const discriminator = Math.min(Math.max(parseInt(param), 1000), 4095);
3192
2832
  this.matterbridgeInformation.matterDiscriminator = discriminator;
@@ -3195,7 +2835,6 @@ export class Matterbridge extends EventEmitter {
3195
2835
  res.json({ message: 'Command received' });
3196
2836
  return;
3197
2837
  }
3198
- // Handle the command setmatterpasscode from Settings
3199
2838
  if (command === 'setmatterpasscode') {
3200
2839
  const passcode = Math.min(Math.max(parseInt(param), 10000000), 90000000);
3201
2840
  this.matterbridgeInformation.matterPasscode = passcode;
@@ -3204,20 +2843,17 @@ export class Matterbridge extends EventEmitter {
3204
2843
  res.json({ message: 'Command received' });
3205
2844
  return;
3206
2845
  }
3207
- // Handle the command setmbloglevel from Settings
3208
2846
  if (command === 'setmblogfile') {
3209
2847
  this.log.debug('Matterbridge file log:', param);
3210
2848
  this.matterbridgeInformation.fileLogger = param === 'true';
3211
2849
  await this.nodeContext?.set('matterbridgeFileLog', param === 'true');
3212
- // Create the file logger for matterbridge
3213
2850
  if (param === 'true')
3214
- AnsiLogger.setGlobalLogfile(path.join(this.matterbridgeDirectory, this.matterbrideLoggerFile), "debug" /* LogLevel.DEBUG */, true);
2851
+ AnsiLogger.setGlobalLogfile(path.join(this.matterbridgeDirectory, this.matterbrideLoggerFile), "debug", true);
3215
2852
  else
3216
2853
  AnsiLogger.setGlobalLogfile(undefined);
3217
2854
  res.json({ message: 'Command received' });
3218
2855
  return;
3219
2856
  }
3220
- // Handle the command setmbloglevel from Settings
3221
2857
  if (command === 'setmjlogfile') {
3222
2858
  this.log.debug('Matter file log:', param);
3223
2859
  this.matterbridgeInformation.matterFileLogger = param === 'true';
@@ -3244,43 +2880,36 @@ export class Matterbridge extends EventEmitter {
3244
2880
  res.json({ message: 'Command received' });
3245
2881
  return;
3246
2882
  }
3247
- // Handle the command unregister from Settings
3248
2883
  if (command === 'unregister') {
3249
2884
  await this.unregisterAndShutdownProcess();
3250
2885
  res.json({ message: 'Command received' });
3251
2886
  return;
3252
2887
  }
3253
- // Handle the command reset from Settings
3254
2888
  if (command === 'reset') {
3255
2889
  await this.shutdownProcessAndReset();
3256
2890
  res.json({ message: 'Command received' });
3257
2891
  return;
3258
2892
  }
3259
- // Handle the command factoryreset from Settings
3260
2893
  if (command === 'factoryreset') {
3261
2894
  await this.shutdownProcessAndFactoryReset();
3262
2895
  res.json({ message: 'Command received' });
3263
2896
  return;
3264
2897
  }
3265
- // Handle the command shutdown from Header
3266
2898
  if (command === 'shutdown') {
3267
2899
  await this.shutdownProcess();
3268
2900
  res.json({ message: 'Command received' });
3269
2901
  return;
3270
2902
  }
3271
- // Handle the command restart from Header
3272
2903
  if (command === 'restart') {
3273
2904
  await this.restartProcess();
3274
2905
  res.json({ message: 'Command received' });
3275
2906
  return;
3276
2907
  }
3277
- // Handle the command update from Header
3278
2908
  if (command === 'update') {
3279
2909
  this.log.info('Updating matterbridge...');
3280
2910
  try {
3281
2911
  await this.spawnCommand('npm', ['install', '-g', 'matterbridge', '--omit=dev', '--verbose']);
3282
2912
  this.log.info('Matterbridge has been updated. Full restart required.');
3283
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
3284
2913
  }
3285
2914
  catch (error) {
3286
2915
  this.log.error('Error updating matterbridge');
@@ -3290,11 +2919,9 @@ export class Matterbridge extends EventEmitter {
3290
2919
  res.json({ message: 'Command received' });
3291
2920
  return;
3292
2921
  }
3293
- // Handle the command saveconfig from Home
3294
2922
  if (command === 'saveconfig') {
3295
2923
  param = param.replace(/\*/g, '\\');
3296
2924
  this.log.info(`Saving config for plugin ${plg}${param}${nf}...`);
3297
- // console.log('Req.body:', JSON.stringify(req.body, null, 2));
3298
2925
  if (!this.plugins.has(param)) {
3299
2926
  this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
3300
2927
  }
@@ -3308,39 +2935,33 @@ export class Matterbridge extends EventEmitter {
3308
2935
  res.json({ message: 'Command received' });
3309
2936
  return;
3310
2937
  }
3311
- // Handle the command installplugin from Home
3312
2938
  if (command === 'installplugin') {
3313
2939
  param = param.replace(/\*/g, '\\');
3314
2940
  this.log.info(`Installing plugin ${plg}${param}${nf}...`);
3315
2941
  try {
3316
2942
  await this.spawnCommand('npm', ['install', '-g', param, '--omit=dev', '--verbose']);
3317
2943
  this.log.info(`Plugin ${plg}${param}${nf} installed. Full restart required.`);
3318
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
3319
2944
  }
3320
2945
  catch (error) {
3321
2946
  this.log.error(`Error installing plugin ${plg}${param}${er}`);
3322
2947
  }
3323
2948
  this.wssSendRestartRequired();
3324
2949
  param = param.split('@')[0];
3325
- // Also add the plugin to matterbridge so no return!
3326
2950
  if (param === 'matterbridge') {
3327
- // If we used the command installplugin to install a dev or a specific version of matterbridge we don't want to add it to matterbridge
3328
2951
  res.json({ message: 'Command received' });
3329
2952
  return;
3330
2953
  }
3331
2954
  }
3332
- // Handle the command addplugin from Home
3333
2955
  if (command === 'addplugin' || command === 'installplugin') {
3334
2956
  param = param.replace(/\*/g, '\\');
3335
2957
  const plugin = await this.plugins.add(param);
3336
2958
  if (plugin) {
3337
- this.plugins.load(plugin, true, 'The plugin has been added', true); // No await do it in the background
2959
+ this.plugins.load(plugin, true, 'The plugin has been added', true);
3338
2960
  }
3339
2961
  res.json({ message: 'Command received' });
3340
2962
  this.wssSendRefreshRequired();
3341
2963
  return;
3342
2964
  }
3343
- // Handle the command removeplugin from Home
3344
2965
  if (command === 'removeplugin') {
3345
2966
  if (!this.plugins.has(param)) {
3346
2967
  this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
@@ -3354,7 +2975,6 @@ export class Matterbridge extends EventEmitter {
3354
2975
  this.wssSendRefreshRequired();
3355
2976
  return;
3356
2977
  }
3357
- // Handle the command enableplugin from Home
3358
2978
  if (command === 'enableplugin') {
3359
2979
  if (!this.plugins.has(param)) {
3360
2980
  this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
@@ -3372,14 +2992,13 @@ export class Matterbridge extends EventEmitter {
3372
2992
  plugin.registeredDevices = undefined;
3373
2993
  plugin.addedDevices = undefined;
3374
2994
  await this.plugins.enable(param);
3375
- this.plugins.load(plugin, true, 'The plugin has been enabled', true); // No await do it in the background
2995
+ this.plugins.load(plugin, true, 'The plugin has been enabled', true);
3376
2996
  }
3377
2997
  }
3378
2998
  res.json({ message: 'Command received' });
3379
2999
  this.wssSendRefreshRequired();
3380
3000
  return;
3381
3001
  }
3382
- // Handle the command disableplugin from Home
3383
3002
  if (command === 'disableplugin') {
3384
3003
  if (!this.plugins.has(param)) {
3385
3004
  this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
@@ -3396,7 +3015,6 @@ export class Matterbridge extends EventEmitter {
3396
3015
  return;
3397
3016
  }
3398
3017
  });
3399
- // Fallback for routing (must be the last route)
3400
3018
  this.expressApp.get('*', (req, res) => {
3401
3019
  this.log.debug('The frontend sent:', req.url);
3402
3020
  this.log.debug('Response send file:', path.join(this.rootDirectory, 'frontend/build/index.html'));
@@ -3404,11 +3022,6 @@ export class Matterbridge extends EventEmitter {
3404
3022
  });
3405
3023
  this.log.debug(`Frontend initialized on port ${YELLOW}${port}${db} static ${UNDERLINE}${path.join(this.rootDirectory, 'frontend/build')}${UNDERLINEOFF}${rs}`);
3406
3024
  }
3407
- /**
3408
- * Retrieves the cluster text description from a given device.
3409
- * @param {MatterbridgeDevice} device - The MatterbridgeDevice object.
3410
- * @returns {string} The attributes description of the cluster servers in the device.
3411
- */
3412
3025
  getClusterTextFromDevice(device) {
3413
3026
  const stringifyUserLabel = (endpoint) => {
3414
3027
  const labelList = endpoint.getClusterServer(UserLabelCluster)?.attributes.labelList.getLocal();
@@ -3431,11 +3044,9 @@ export class Matterbridge extends EventEmitter {
3431
3044
  return '';
3432
3045
  };
3433
3046
  let attributes = '';
3434
- // this.log.debug(`***getClusterTextFromDevice: ${device.deviceName} (${device.name})`);
3435
3047
  const clusterServers = device.getAllClusterServers();
3436
3048
  clusterServers.forEach((clusterServer) => {
3437
3049
  try {
3438
- // this.log.debug(`**--clusterServer: ${clusterServer.id} (${clusterServer.name})`);
3439
3050
  if (clusterServer.name === 'OnOff')
3440
3051
  attributes += `OnOff: ${clusterServer.attributes.onOff.getLocal()} `;
3441
3052
  if (clusterServer.name === 'Switch')
@@ -3486,30 +3097,18 @@ export class Matterbridge extends EventEmitter {
3486
3097
  attributes += `${stringifyFixedLabel(device)} `;
3487
3098
  if (clusterServer.name === 'UserLabel')
3488
3099
  attributes += `${stringifyUserLabel(device)} `;
3489
- // this.log.debug(`*--clusterServer: ${clusterServer.id} (${clusterServer.name})`);
3490
3100
  }
3491
3101
  catch (error) {
3492
3102
  this.log.error(`getClusterTextFromDevice with ${clusterServer.name} error: ${error}`);
3493
3103
  }
3494
3104
  });
3495
- // this.log.debug(`*getClusterTextFromDevice: ${device.deviceName} (${device.name})`);
3496
3105
  return attributes;
3497
3106
  }
3498
- /**
3499
- * Initializes the Matterbridge instance as extension for zigbee2mqtt.
3500
- * @deprecated This method is deprecated and will be removed in a future version.
3501
- *
3502
- * @returns A Promise that resolves when the initialization is complete.
3503
- */
3504
3107
  async startExtension(dataPath, extensionVersion, port = 5540) {
3505
- // Set the bridge mode
3506
3108
  this.bridgeMode = 'bridge';
3507
- // Set the first port to use
3508
3109
  this.port = port;
3509
- // Set Matterbridge logger
3510
- this.log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: "info" /* LogLevel.INFO */ });
3110
+ this.log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4, logLevel: "info" });
3511
3111
  this.log.debug('Matterbridge extension is starting...');
3512
- // Initialize NodeStorage
3513
3112
  this.matterbridgeDirectory = dataPath;
3514
3113
  this.log.debug('Creating node storage manager dir: ' + path.join(this.matterbridgeDirectory, 'node_storage'));
3515
3114
  this.nodeStorage = new NodeStorageManager({ dir: path.join(this.matterbridgeDirectory, 'node_storage'), logging: false });
@@ -3528,13 +3127,10 @@ export class Matterbridge extends EventEmitter {
3528
3127
  };
3529
3128
  this.plugins.set(plugin);
3530
3129
  this.plugins.saveToStorage();
3531
- // Log system info and create .matterbridge directory
3532
3130
  await this.logNodeAndSystemInfo();
3533
3131
  this.matterbridgeDirectory = dataPath;
3534
- // Set matter.js logger level and format
3535
3132
  Logger.defaultLogLevel = MatterLogLevel.INFO;
3536
3133
  Logger.format = MatterLogFormat.ANSI;
3537
- // Start the storage and create matterbridgeContext
3538
3134
  await this.startMatterStorage('json', path.join(this.matterbridgeDirectory, this.matterStorageName));
3539
3135
  if (!this.storageManager)
3540
3136
  return false;
@@ -3544,7 +3140,7 @@ export class Matterbridge extends EventEmitter {
3544
3140
  await this.matterbridgeContext.set('softwareVersion', 1);
3545
3141
  await this.matterbridgeContext.set('softwareVersionString', this.matterbridgeVersion);
3546
3142
  await this.matterbridgeContext.set('hardwareVersion', 1);
3547
- await this.matterbridgeContext.set('hardwareVersionString', extensionVersion); // Update with the extension version
3143
+ await this.matterbridgeContext.set('hardwareVersionString', extensionVersion);
3548
3144
  this.matterServer = this.createMatterServer(this.storageManager);
3549
3145
  this.log.debug(`Creating commissioning server for ${plg}Matterbridge${db}`);
3550
3146
  this.commissioningServer = await this.createCommisioningServer(this.matterbridgeContext, 'Matterbridge');
@@ -3557,7 +3153,6 @@ export class Matterbridge extends EventEmitter {
3557
3153
  await this.startMatterServer();
3558
3154
  this.log.info('Matter server started');
3559
3155
  await this.showCommissioningQRCode(this.commissioningServer, this.matterbridgeContext, this.nodeContext, 'Matterbridge');
3560
- // Set reachability to true and trigger event after 60 seconds
3561
3156
  setTimeout(() => {
3562
3157
  this.log.info(`Setting reachability to true for ${plg}Matterbridge${db}`);
3563
3158
  if (this.commissioningServer)
@@ -3567,31 +3162,14 @@ export class Matterbridge extends EventEmitter {
3567
3162
  }, 60 * 1000);
3568
3163
  return this.commissioningServer.isCommissioned();
3569
3164
  }
3570
- /**
3571
- * Close the Matterbridge instance as extension for zigbee2mqtt.
3572
- * @deprecated This method is deprecated and will be removed in a future version.
3573
- *
3574
- * @returns A Promise that resolves when the initialization is complete.
3575
- */
3576
3165
  async stopExtension() {
3577
- // Closing matter
3578
3166
  await this.stopMatterServer();
3579
- // Clearing the session manager
3580
- // this.matterbridgeContext?.createContext('SessionManager').clear();
3581
- // Closing storage
3582
3167
  await this.stopMatterStorage();
3583
3168
  this.log.info('Matter server stopped');
3584
3169
  }
3585
- /**
3586
- * Checks if the extension is commissioned.
3587
- * @deprecated This method is deprecated and will be removed in a future version.
3588
- *
3589
- * @returns {boolean} Returns true if the extension is commissioned, false otherwise.
3590
- */
3591
3170
  isExtensionCommissioned() {
3592
3171
  if (!this.commissioningServer)
3593
3172
  return false;
3594
3173
  return this.commissioningServer.isCommissioned();
3595
3174
  }
3596
3175
  }
3597
- //# sourceMappingURL=matterbridge.js.map