matterbridge 1.6.7 → 1.6.8-dev.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/dist/cli.js +0 -26
  3. package/dist/cluster/export.js +0 -2
  4. package/dist/defaultConfigSchema.js +0 -23
  5. package/dist/deviceManager.js +1 -26
  6. package/dist/index.js +0 -30
  7. package/dist/logger/export.js +0 -1
  8. package/dist/matter/export.js +5 -1
  9. package/dist/matterbridge.js +61 -659
  10. package/dist/matterbridgeAccessoryPlatform.js +0 -33
  11. package/dist/matterbridgeBehaviors.js +1 -29
  12. package/dist/matterbridgeDevice.js +9 -986
  13. package/dist/matterbridgeDeviceTypes.js +11 -82
  14. package/dist/matterbridgeDynamicPlatform.js +0 -33
  15. package/dist/matterbridgeEdge.js +1 -532
  16. package/dist/matterbridgeEndpoint.js +12 -1111
  17. package/dist/matterbridgePlatform.js +3 -91
  18. package/dist/matterbridgeTypes.js +0 -24
  19. package/dist/matterbridgeWebsocket.js +0 -45
  20. package/dist/pluginManager.js +3 -238
  21. package/dist/storage/export.js +0 -1
  22. package/dist/utils/colorUtils.js +2 -205
  23. package/dist/utils/export.js +0 -1
  24. package/dist/utils/utils.js +7 -252
  25. package/npm-shrinkwrap.json +7 -71
  26. package/package.json +1 -2
  27. package/dist/cli.d.ts +0 -25
  28. package/dist/cli.d.ts.map +0 -1
  29. package/dist/cli.js.map +0 -1
  30. package/dist/cluster/export.d.ts +0 -2
  31. package/dist/cluster/export.d.ts.map +0 -1
  32. package/dist/cluster/export.js.map +0 -1
  33. package/dist/defaultConfigSchema.d.ts +0 -27
  34. package/dist/defaultConfigSchema.d.ts.map +0 -1
  35. package/dist/defaultConfigSchema.js.map +0 -1
  36. package/dist/deviceManager.d.ts +0 -46
  37. package/dist/deviceManager.d.ts.map +0 -1
  38. package/dist/deviceManager.js.map +0 -1
  39. package/dist/index.d.ts +0 -40
  40. package/dist/index.d.ts.map +0 -1
  41. package/dist/index.js.map +0 -1
  42. package/dist/logger/export.d.ts +0 -2
  43. package/dist/logger/export.d.ts.map +0 -1
  44. package/dist/logger/export.js.map +0 -1
  45. package/dist/matter/export.d.ts +0 -6
  46. package/dist/matter/export.d.ts.map +0 -1
  47. package/dist/matter/export.js.map +0 -1
  48. package/dist/matterbridge.d.ts +0 -466
  49. package/dist/matterbridge.d.ts.map +0 -1
  50. package/dist/matterbridge.js.map +0 -1
  51. package/dist/matterbridgeAccessoryPlatform.d.ts +0 -39
  52. package/dist/matterbridgeAccessoryPlatform.d.ts.map +0 -1
  53. package/dist/matterbridgeAccessoryPlatform.js.map +0 -1
  54. package/dist/matterbridgeBehaviors.d.ts +0 -942
  55. package/dist/matterbridgeBehaviors.d.ts.map +0 -1
  56. package/dist/matterbridgeBehaviors.js.map +0 -1
  57. package/dist/matterbridgeDevice.d.ts +0 -7063
  58. package/dist/matterbridgeDevice.d.ts.map +0 -1
  59. package/dist/matterbridgeDevice.js.map +0 -1
  60. package/dist/matterbridgeDeviceTypes.d.ts +0 -109
  61. package/dist/matterbridgeDeviceTypes.d.ts.map +0 -1
  62. package/dist/matterbridgeDeviceTypes.js.map +0 -1
  63. package/dist/matterbridgeDynamicPlatform.d.ts +0 -39
  64. package/dist/matterbridgeDynamicPlatform.d.ts.map +0 -1
  65. package/dist/matterbridgeDynamicPlatform.js.map +0 -1
  66. package/dist/matterbridgeEdge.d.ts +0 -92
  67. package/dist/matterbridgeEdge.d.ts.map +0 -1
  68. package/dist/matterbridgeEdge.js.map +0 -1
  69. package/dist/matterbridgeEndpoint.d.ts +0 -10164
  70. package/dist/matterbridgeEndpoint.d.ts.map +0 -1
  71. package/dist/matterbridgeEndpoint.js.map +0 -1
  72. package/dist/matterbridgePlatform.d.ts +0 -114
  73. package/dist/matterbridgePlatform.d.ts.map +0 -1
  74. package/dist/matterbridgePlatform.js.map +0 -1
  75. package/dist/matterbridgeTypes.d.ts +0 -162
  76. package/dist/matterbridgeTypes.d.ts.map +0 -1
  77. package/dist/matterbridgeTypes.js.map +0 -1
  78. package/dist/matterbridgeWebsocket.d.ts +0 -49
  79. package/dist/matterbridgeWebsocket.d.ts.map +0 -1
  80. package/dist/matterbridgeWebsocket.js.map +0 -1
  81. package/dist/pluginManager.d.ts +0 -238
  82. package/dist/pluginManager.d.ts.map +0 -1
  83. package/dist/pluginManager.js.map +0 -1
  84. package/dist/storage/export.d.ts +0 -2
  85. package/dist/storage/export.d.ts.map +0 -1
  86. package/dist/storage/export.js.map +0 -1
  87. package/dist/utils/colorUtils.d.ts +0 -61
  88. package/dist/utils/colorUtils.d.ts.map +0 -1
  89. package/dist/utils/colorUtils.js.map +0 -1
  90. package/dist/utils/export.d.ts +0 -3
  91. package/dist/utils/export.d.ts.map +0 -1
  92. package/dist/utils/export.js.map +0 -1
  93. package/dist/utils/utils.d.ts +0 -221
  94. package/dist/utils/utils.d.ts.map +0 -1
  95. 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,26 @@ 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
20
  import { DeviceTypeId, Logger, LogLevel as MatterLogLevel, LogFormat as MatterLogFormat, VendorId, StorageManager, EndpointServer } 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
55
26
  const plg = '\u001B[38;5;33m';
56
27
  const dev = '\u001B[38;5;79m';
57
28
  const typ = '\u001B[38;5;207m';
58
- /**
59
- * Represents the Matterbridge application.
60
- */
61
29
  export class Matterbridge extends EventEmitter {
62
30
  systemInformation = {
63
31
  interfaceName: '',
@@ -94,7 +62,7 @@ export class Matterbridge extends EventEmitter {
94
62
  edge: hasParameter('edge'),
95
63
  readOnly: hasParameter('readonly'),
96
64
  profile: getParameter('profile'),
97
- loggerLevel: "info" /* LogLevel.INFO */,
65
+ loggerLevel: "info",
98
66
  fileLogger: false,
99
67
  matterLoggerLevel: MatterLogLevel.INFO,
100
68
  matterFileLogger: false,
@@ -133,7 +101,6 @@ export class Matterbridge extends EventEmitter {
133
101
  nodeContext;
134
102
  matterStorageName = 'matterbridge' + (getParameter('profile') ? '.' + getParameter('profile') : '') + '.json';
135
103
  nodeStorageName = 'storage' + (getParameter('profile') ? '.' + getParameter('profile') : '');
136
- // Cleanup
137
104
  hasCleanupStarted = false;
138
105
  initialized = false;
139
106
  execRunningCount = 0;
@@ -145,18 +112,16 @@ export class Matterbridge extends EventEmitter {
145
112
  sigtermHandler;
146
113
  exceptionHandler;
147
114
  rejectionHandler;
148
- // Frontend
149
115
  expressApp;
150
116
  httpServer;
151
117
  httpsServer;
152
118
  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
119
+ mdnsInterface;
120
+ ipv4address;
121
+ ipv6address;
122
+ port = 5540;
123
+ passcode;
124
+ discriminator;
160
125
  storageManager;
161
126
  matterbridgeContext;
162
127
  mattercontrollerContext;
@@ -167,26 +132,13 @@ export class Matterbridge extends EventEmitter {
167
132
  aggregatorVendorId = VendorId(getIntParameter('vendorId') ?? 0xfff1);
168
133
  aggregatorProductId = getIntParameter('productId') ?? 0x8000;
169
134
  static instance;
170
- // We load asyncronously so is private
171
135
  constructor() {
172
136
  super();
173
- // Bind the handler to the instance
174
137
  this.matterbridgeMessageHandler = wsMessageHandler.bind(this);
175
138
  }
176
139
  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
140
  static async loadInstance(initialize = false) {
188
141
  if (!Matterbridge.instance) {
189
- // eslint-disable-next-line no-console
190
142
  if (hasParameter('debug'))
191
143
  console.log(GREEN + 'Creating a new instance of Matterbridge.', initialize ? 'Initializing...' : 'Not initializing...', rs);
192
144
  Matterbridge.instance = new Matterbridge();
@@ -195,11 +147,6 @@ export class Matterbridge extends EventEmitter {
195
147
  }
196
148
  return Matterbridge.instance;
197
149
  }
198
- /**
199
- * Call cleanup().
200
- * @deprecated This method is deprecated and is only used for jest tests.
201
- *
202
- */
203
150
  async destroyInstance() {
204
151
  await this.cleanup('destroying instance...', false);
205
152
  await waiter('destroying instance...', () => {
@@ -207,60 +154,39 @@ export class Matterbridge extends EventEmitter {
207
154
  }, false, 60000, 100, false);
208
155
  await wait(1000, 'Wait for the global node_modules and matterbridge version', false);
209
156
  }
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
157
  async initialize() {
221
- // Set the restart mode
222
158
  if (hasParameter('service'))
223
159
  this.restartMode = 'service';
224
160
  if (hasParameter('docker'))
225
161
  this.restartMode = 'docker';
226
- // Set the matterbridge directory
227
162
  this.homeDirectory = getParameter('homedir') ?? os.homedir();
228
163
  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
164
+ this.log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4, logLevel: hasParameter('debug') ? "debug" : "info" });
232
165
  try {
233
166
  this.log.debug(`Creating node storage manager: ${CYAN}${this.nodeStorageName}${db}`);
234
167
  this.nodeStorage = new NodeStorageManager({ dir: path.join(this.matterbridgeDirectory, this.nodeStorageName), writeQueue: false, expiredInterval: undefined, logging: false });
235
168
  this.log.debug('Creating node storage context for matterbridge');
236
169
  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
170
  const keys = (await this.nodeStorage?.storage.keys());
240
171
  for (const key of keys) {
241
172
  this.log.debug(`Checking node storage manager key: ${CYAN}${key}${db}`);
242
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
243
173
  await this.nodeStorage?.storage.get(key);
244
174
  }
245
175
  const storages = await this.nodeStorage.getStorageNames();
246
176
  for (const storage of storages) {
247
177
  this.log.debug(`Checking storage: ${CYAN}${storage}${db}`);
248
178
  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
179
  const keys = (await nodeContext?.storage.keys());
252
180
  keys.forEach(async (key) => {
253
181
  this.log.debug(`Checking key: ${CYAN}${storage}:${key}${db}`);
254
182
  await nodeContext?.get(key);
255
183
  });
256
184
  }
257
- // Creating a backup of the node storage since it is not corrupted
258
185
  this.log.debug('Creating node storage backup...');
259
186
  await copyDirectory(path.join(this.matterbridgeDirectory, this.nodeStorageName), path.join(this.matterbridgeDirectory, this.nodeStorageName + '.backup'));
260
187
  this.log.debug('Created node storage backup');
261
188
  }
262
189
  catch (error) {
263
- // Restoring the backup of the node storage since it is corrupted
264
190
  this.log.error(`Error creating node storage manager and context: ${error instanceof Error ? error.message : error}`);
265
191
  if (hasParameter('norestore')) {
266
192
  this.log.fatal(`The matterbridge node storage is corrupted. Parameter -norestore found: exiting...`);
@@ -275,51 +201,45 @@ export class Matterbridge extends EventEmitter {
275
201
  this.log.fatal('Fatal error creating node storage manager and context for matterbridge');
276
202
  throw new Error('Fatal error creating node storage manager and context for matterbridge');
277
203
  }
278
- // Set the first port to use for the commissioning server (will be incremented in childbridge mode)
279
204
  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
205
  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
206
  this.discriminator = this.discriminator ?? getIntParameter('discriminator') ?? (await this.nodeContext.get('matterdiscriminator'));
284
207
  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
208
  if (hasParameter('logger')) {
287
209
  const level = getParameter('logger');
288
210
  if (level === 'debug') {
289
- this.log.logLevel = "debug" /* LogLevel.DEBUG */;
211
+ this.log.logLevel = "debug";
290
212
  }
291
213
  else if (level === 'info') {
292
- this.log.logLevel = "info" /* LogLevel.INFO */;
214
+ this.log.logLevel = "info";
293
215
  }
294
216
  else if (level === 'notice') {
295
- this.log.logLevel = "notice" /* LogLevel.NOTICE */;
217
+ this.log.logLevel = "notice";
296
218
  }
297
219
  else if (level === 'warn') {
298
- this.log.logLevel = "warn" /* LogLevel.WARN */;
220
+ this.log.logLevel = "warn";
299
221
  }
300
222
  else if (level === 'error') {
301
- this.log.logLevel = "error" /* LogLevel.ERROR */;
223
+ this.log.logLevel = "error";
302
224
  }
303
225
  else if (level === 'fatal') {
304
- this.log.logLevel = "fatal" /* LogLevel.FATAL */;
226
+ this.log.logLevel = "fatal";
305
227
  }
306
228
  else {
307
229
  this.log.warn(`Invalid matterbridge logger level: ${level}. Using default level "info".`);
308
- this.log.logLevel = "info" /* LogLevel.INFO */;
230
+ this.log.logLevel = "info";
309
231
  }
310
232
  }
311
233
  else {
312
- this.log.logLevel = await this.nodeContext.get('matterbridgeLogLevel', "info" /* LogLevel.INFO */);
234
+ this.log.logLevel = await this.nodeContext.get('matterbridgeLogLevel', "info");
313
235
  }
314
236
  MatterbridgeDevice.logLevel = this.log.logLevel;
315
- // Create the file logger for matterbridge (context: matterbridgeFileLog)
316
237
  if (hasParameter('filelogger') || (await this.nodeContext.get('matterbridgeFileLog', false))) {
317
238
  AnsiLogger.setGlobalLogfile(path.join(this.matterbridgeDirectory, this.matterbrideLoggerFile), this.log.logLevel, true);
318
239
  this.matterbridgeInformation.fileLogger = true;
319
240
  }
320
241
  this.log.notice('Matterbridge is starting...');
321
242
  this.log.debug(`Matterbridge logLevel: ${this.log.logLevel} fileLoger: ${this.matterbridgeInformation.fileLogger}.`);
322
- // Set matter.js logger level, format and logger (context: matterLogLevel)
323
243
  if (hasParameter('matterlogger')) {
324
244
  const level = getParameter('matterlogger');
325
245
  if (level === 'debug') {
@@ -350,7 +270,6 @@ export class Matterbridge extends EventEmitter {
350
270
  }
351
271
  Logger.format = MatterLogFormat.ANSI;
352
272
  Logger.setLogger('default', this.createMatterLogger());
353
- // Create the file logger for matter.js (context: matterFileLog)
354
273
  if (hasParameter('matterfilelogger') || (await this.nodeContext.get('matterFileLog', false))) {
355
274
  this.matterbridgeInformation.matterFileLogger = true;
356
275
  Logger.addLogger('matterfilelogger', await this.createMatterFileLogger(path.join(this.matterbridgeDirectory, this.matterLoggerFile), true), {
@@ -359,7 +278,6 @@ export class Matterbridge extends EventEmitter {
359
278
  });
360
279
  }
361
280
  this.log.debug(`Matter logLevel: ${Logger.defaultLogLevel} fileLoger: ${this.matterbridgeInformation.matterFileLogger}.`);
362
- // Set the interface to use for the matter server mdnsInterface
363
281
  if (hasParameter('mdnsinterface')) {
364
282
  this.mdnsInterface = getParameter('mdnsinterface');
365
283
  }
@@ -368,7 +286,6 @@ export class Matterbridge extends EventEmitter {
368
286
  if (this.mdnsInterface === '')
369
287
  this.mdnsInterface = undefined;
370
288
  }
371
- // Set the listeningAddressIpv4 for the matter commissioning server
372
289
  if (hasParameter('ipv4address')) {
373
290
  this.ipv4address = getParameter('ipv4address');
374
291
  }
@@ -377,7 +294,6 @@ export class Matterbridge extends EventEmitter {
377
294
  if (this.ipv4address === '')
378
295
  this.ipv4address = undefined;
379
296
  }
380
- // Set the listeningAddressIpv6 for the matter commissioning server
381
297
  if (hasParameter('ipv6address')) {
382
298
  this.ipv6address = getParameter('ipv6address');
383
299
  }
@@ -386,23 +302,17 @@ export class Matterbridge extends EventEmitter {
386
302
  if (this.ipv6address === '')
387
303
  this.ipv6address = undefined;
388
304
  }
389
- // Initialize PluginManager
390
305
  this.plugins = new PluginManager(this);
391
306
  await this.plugins.loadFromStorage();
392
- // Initialize DeviceManager
393
307
  this.devices = new DeviceManager(this, this.nodeContext);
394
- // Get the plugins from node storage and create the plugins node storage contexts
395
308
  for (const plugin of this.plugins) {
396
309
  const packageJson = await this.plugins.parse(plugin);
397
310
  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
311
  this.log.info(`Error parsing plugin ${plg}${plugin.name}${nf}. Trying to reinstall it from npm.`);
401
312
  try {
402
313
  await this.spawnCommand('npm', ['install', '-g', plugin.name, '--omit=dev', '--verbose']);
403
314
  this.log.info(`Plugin ${plg}${plugin.name}${nf} reinstalled.`);
404
315
  plugin.error = false;
405
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
406
316
  }
407
317
  catch (error) {
408
318
  plugin.error = true;
@@ -419,7 +329,6 @@ export class Matterbridge extends EventEmitter {
419
329
  await plugin.nodeContext.set('description', plugin.description);
420
330
  await plugin.nodeContext.set('author', plugin.author);
421
331
  }
422
- // Log system info and create .matterbridge directory
423
332
  await this.logNodeAndSystemInfo();
424
333
  this.log.notice(`Matterbridge version ${this.matterbridgeVersion} ` +
425
334
  `${hasParameter('bridge') || (!hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'bridge') ? 'mode bridge ' : ''}` +
@@ -427,7 +336,6 @@ export class Matterbridge extends EventEmitter {
427
336
  `${hasParameter('controller') ? 'mode controller ' : ''}` +
428
337
  `${this.restartMode !== '' ? 'restart mode ' + this.restartMode + ' ' : ''}` +
429
338
  `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
339
  const minNodeVersion = 18;
432
340
  const nodeVersion = process.versions.node;
433
341
  const versionMajor = parseInt(nodeVersion.split('.')[0]);
@@ -435,17 +343,10 @@ export class Matterbridge extends EventEmitter {
435
343
  this.log.error(`Node version ${versionMajor} is not supported. Please upgrade to ${minNodeVersion} or above.`);
436
344
  throw new Error(`Node version ${versionMajor} is not supported. Please upgrade to ${minNodeVersion} or above.`);
437
345
  }
438
- // Register process handlers
439
346
  this.registerProcessHandlers();
440
- // Parse command line
441
347
  await this.parseCommandLine();
442
348
  this.initialized = true;
443
349
  }
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
350
  async parseCommandLine() {
450
351
  if (hasParameter('help')) {
451
352
  this.log.info(`\nUsage: matterbridge [options]\n
@@ -553,14 +454,12 @@ export class Matterbridge extends EventEmitter {
553
454
  }
554
455
  if (hasParameter('factoryreset')) {
555
456
  try {
556
- // Delete matter storage file
557
457
  await fs.unlink(path.join(this.matterbridgeDirectory, this.matterStorageName));
558
458
  }
559
459
  catch (err) {
560
460
  this.log.error(`Error deleting storage: ${err}`);
561
461
  }
562
462
  try {
563
- // Delete node storage directory with its subdirectories
564
463
  await fs.rm(path.join(this.matterbridgeDirectory, this.nodeStorageName), { recursive: true });
565
464
  }
566
465
  catch (err) {
@@ -574,7 +473,6 @@ export class Matterbridge extends EventEmitter {
574
473
  this.emit('shutdown');
575
474
  return;
576
475
  }
577
- // Start the matter storage and create the matterbridge context
578
476
  try {
579
477
  await this.startMatterStorage('json', path.join(this.matterbridgeDirectory, this.matterStorageName));
580
478
  }
@@ -609,34 +507,28 @@ export class Matterbridge extends EventEmitter {
609
507
  this.emit('shutdown');
610
508
  return;
611
509
  }
612
- // Initialize frontend
613
510
  if (getIntParameter('frontend') !== 0 || getIntParameter('frontend') === undefined)
614
511
  await this.initializeFrontend(getIntParameter('frontend'));
615
- // Check each 60 minutes the latest versions
616
512
  this.checkUpdateInterval = setInterval(() => {
617
513
  this.getMatterbridgeLatestVersion();
618
514
  for (const plugin of this.plugins) {
619
515
  this.getPluginLatestVersion(plugin);
620
516
  }
621
517
  }, 60 * 60 * 1000);
622
- // Start the matterbridge in mode test
623
518
  if (hasParameter('test')) {
624
519
  this.bridgeMode = 'bridge';
625
520
  MatterbridgeDevice.bridgeMode = 'bridge';
626
521
  return;
627
522
  }
628
- // Start the matterbridge in mode controller
629
523
  if (hasParameter('controller')) {
630
524
  this.bridgeMode = 'controller';
631
525
  await this.startController();
632
526
  return;
633
527
  }
634
- // Check if the bridge mode is set and start matterbridge in bridge mode if not set
635
528
  if (!hasParameter('bridge') && !hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === '') {
636
529
  this.log.info('Setting default matterbridge start mode to bridge');
637
530
  await this.nodeContext?.set('bridgeMode', 'bridge');
638
531
  }
639
- // Start matterbridge in bridge mode
640
532
  if (hasParameter('bridge') || (!hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'bridge')) {
641
533
  this.bridgeMode = 'bridge';
642
534
  MatterbridgeDevice.bridgeMode = 'bridge';
@@ -645,7 +537,6 @@ export class Matterbridge extends EventEmitter {
645
537
  await this.startBridge();
646
538
  return;
647
539
  }
648
- // Start matterbridge in childbridge mode
649
540
  if (hasParameter('childbridge') || (!hasParameter('bridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'childbridge')) {
650
541
  this.bridgeMode = 'childbridge';
651
542
  MatterbridgeDevice.bridgeMode = 'childbridge';
@@ -655,28 +546,17 @@ export class Matterbridge extends EventEmitter {
655
546
  return;
656
547
  }
657
548
  }
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
549
  async startPlugins() {
667
- // Check, load and start the plugins
668
550
  for (const plugin of this.plugins) {
669
551
  plugin.configJson = await this.plugins.loadConfig(plugin);
670
552
  plugin.schemaJson = await this.plugins.loadSchema(plugin);
671
- // Check if the plugin is available
672
553
  if (!(await this.plugins.resolve(plugin.path))) {
673
554
  this.log.error(`Plugin ${plg}${plugin.name}${er} not found or not validated. Disabling it.`);
674
555
  plugin.enabled = false;
675
556
  plugin.error = true;
676
557
  continue;
677
558
  }
678
- // Check if the plugin has a new version
679
- this.getPluginLatestVersion(plugin); // No await do it asyncronously
559
+ this.getPluginLatestVersion(plugin);
680
560
  if (!plugin.enabled) {
681
561
  this.log.info(`Plugin ${plg}${plugin.name}${nf} not enabled`);
682
562
  continue;
@@ -691,26 +571,20 @@ export class Matterbridge extends EventEmitter {
691
571
  plugin.addedDevices = undefined;
692
572
  plugin.qrPairingCode = undefined;
693
573
  plugin.manualPairingCode = undefined;
694
- this.plugins.load(plugin, true, 'Matterbridge is starting'); // No await do it asyncronously
574
+ this.plugins.load(plugin, true, 'Matterbridge is starting');
695
575
  }
696
576
  this.wssSendRefreshRequired();
697
577
  }
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
578
  registerProcessHandlers() {
703
579
  this.log.debug(`Registering uncaughtException and unhandledRejection handlers...`);
704
580
  process.removeAllListeners('uncaughtException');
705
581
  process.removeAllListeners('unhandledRejection');
706
582
  this.exceptionHandler = async (error) => {
707
583
  this.log.fatal('Unhandled Exception detected at:', error.stack || error, rs);
708
- // await this.cleanup('Unhandled Exception detected, cleaning up...');
709
584
  };
710
585
  process.on('uncaughtException', this.exceptionHandler);
711
586
  this.rejectionHandler = async (reason, promise) => {
712
587
  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
588
  };
715
589
  process.on('unhandledRejection', this.rejectionHandler);
716
590
  this.log.debug(`Registering SIGINT and SIGTERM signal handlers...`);
@@ -723,9 +597,6 @@ export class Matterbridge extends EventEmitter {
723
597
  };
724
598
  process.on('SIGTERM', this.sigtermHandler);
725
599
  }
726
- /**
727
- * Deregisters the process uncaughtException, unhandledRejection, SIGINT and SIGTERM signal handlers.
728
- */
729
600
  deregisterProcesslHandlers() {
730
601
  this.log.debug(`Deregistering uncaughtException and unhandledRejection handlers...`);
731
602
  if (this.exceptionHandler)
@@ -742,11 +613,7 @@ export class Matterbridge extends EventEmitter {
742
613
  process.off('SIGTERM', this.sigtermHandler);
743
614
  this.sigtermHandler = undefined;
744
615
  }
745
- /**
746
- * Logs the node and system information.
747
- */
748
616
  async logNodeAndSystemInfo() {
749
- // IP address information
750
617
  const networkInterfaces = os.networkInterfaces();
751
618
  this.systemInformation.ipv4Address = '';
752
619
  this.systemInformation.ipv6Address = '';
@@ -766,7 +633,7 @@ export class Matterbridge extends EventEmitter {
766
633
  this.systemInformation.macAddress = detail.mac;
767
634
  }
768
635
  }
769
- if (this.systemInformation.ipv4Address !== '' /* && this.systemInformation.ipv6Address !== ''*/) {
636
+ if (this.systemInformation.ipv4Address !== '') {
770
637
  this.log.debug(`Using interface: '${this.systemInformation.interfaceName}'`);
771
638
  this.log.debug(`- with MAC address: '${this.systemInformation.macAddress}'`);
772
639
  this.log.debug(`- with IPv4 address: '${this.systemInformation.ipv4Address}'`);
@@ -774,22 +641,19 @@ export class Matterbridge extends EventEmitter {
774
641
  break;
775
642
  }
776
643
  }
777
- // Node information
778
644
  this.systemInformation.nodeVersion = process.versions.node;
779
645
  const versionMajor = parseInt(this.systemInformation.nodeVersion.split('.')[0]);
780
646
  const versionMinor = parseInt(this.systemInformation.nodeVersion.split('.')[1]);
781
647
  const versionPatch = parseInt(this.systemInformation.nodeVersion.split('.')[2]);
782
- // Host system information
783
648
  this.systemInformation.hostname = os.hostname();
784
649
  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
650
+ this.systemInformation.osType = os.type();
651
+ this.systemInformation.osRelease = os.release();
652
+ this.systemInformation.osPlatform = os.platform();
653
+ this.systemInformation.osArch = os.arch();
654
+ this.systemInformation.totalMemory = (os.totalmem() / 1024 / 1024 / 1024).toFixed(2) + ' GB';
655
+ this.systemInformation.freeMemory = (os.freemem() / 1024 / 1024 / 1024).toFixed(2) + ' GB';
656
+ this.systemInformation.systemUptime = (os.uptime() / 60 / 60).toFixed(2) + ' hours';
793
657
  this.log.debug('Host System Information:');
794
658
  this.log.debug(`- Hostname: ${this.systemInformation.hostname}`);
795
659
  this.log.debug(`- User: ${this.systemInformation.user}`);
@@ -805,19 +669,15 @@ export class Matterbridge extends EventEmitter {
805
669
  this.log.debug(`- Total Memory: ${this.systemInformation.totalMemory}`);
806
670
  this.log.debug(`- Free Memory: ${this.systemInformation.freeMemory}`);
807
671
  this.log.debug(`- System Uptime: ${this.systemInformation.systemUptime}`);
808
- // Home directory
809
672
  this.homeDirectory = getParameter('homedir') ?? os.homedir();
810
673
  this.matterbridgeInformation.homeDirectory = this.homeDirectory;
811
674
  this.log.debug(`Home Directory: ${this.homeDirectory}`);
812
- // Package root directory
813
675
  const currentFileDirectory = path.dirname(fileURLToPath(import.meta.url));
814
676
  this.rootDirectory = path.resolve(currentFileDirectory, '../');
815
677
  this.matterbridgeInformation.rootDirectory = this.rootDirectory;
816
678
  this.log.debug(`Root Directory: ${this.rootDirectory}`);
817
- // Global node_modules directory
818
679
  if (this.nodeContext)
819
680
  this.globalModulesDirectory = await this.nodeContext.get('globalModulesDirectory', '');
820
- // First run of Matterbridge so the node storage is empty
821
681
  if (this.globalModulesDirectory === '') {
822
682
  try {
823
683
  this.globalModulesDirectory = await this.getGlobalNodeModules();
@@ -841,7 +701,6 @@ export class Matterbridge extends EventEmitter {
841
701
  this.log.error(`Error getting global node_modules directory: ${error}`);
842
702
  });
843
703
  }
844
- // Create the data directory .matterbridge in the home directory
845
704
  this.matterbridgeDirectory = path.join(this.homeDirectory, '.matterbridge');
846
705
  this.matterbridgeInformation.matterbridgeDirectory = this.matterbridgeDirectory;
847
706
  try {
@@ -865,7 +724,6 @@ export class Matterbridge extends EventEmitter {
865
724
  }
866
725
  }
867
726
  this.log.debug(`Matterbridge Directory: ${this.matterbridgeDirectory}`);
868
- // Create the plugin directory Matterbridge in the home directory
869
727
  this.matterbridgePluginDirectory = path.join(this.homeDirectory, 'Matterbridge');
870
728
  this.matterbridgeInformation.matterbridgePluginDirectory = this.matterbridgePluginDirectory;
871
729
  try {
@@ -889,28 +747,19 @@ export class Matterbridge extends EventEmitter {
889
747
  }
890
748
  }
891
749
  this.log.debug(`Matterbridge Plugin Directory: ${this.matterbridgePluginDirectory}`);
892
- // Matterbridge version
893
750
  const packageJson = JSON.parse(await fs.readFile(path.join(this.rootDirectory, 'package.json'), 'utf-8'));
894
751
  this.matterbridgeVersion = packageJson.version;
895
752
  this.matterbridgeInformation.matterbridgeVersion = this.matterbridgeVersion;
896
753
  this.log.debug(`Matterbridge Version: ${this.matterbridgeVersion}`);
897
- // Matterbridge latest version
898
754
  if (this.nodeContext)
899
755
  this.matterbridgeLatestVersion = await this.nodeContext.get('matterbridgeLatestVersion', '');
900
756
  this.log.debug(`Matterbridge Latest Version: ${this.matterbridgeLatestVersion}`);
901
757
  this.getMatterbridgeLatestVersion();
902
- // Current working directory
903
758
  const currentDir = process.cwd();
904
759
  this.log.debug(`Current Working Directory: ${currentDir}`);
905
- // Command line arguments (excluding 'node' and the script name)
906
760
  const cmdArgs = process.argv.slice(2).join(' ');
907
761
  this.log.debug(`Command Line Arguments: ${cmdArgs}`);
908
762
  }
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
763
  async getLatestVersion(packageName) {
915
764
  return new Promise((resolve, reject) => {
916
765
  this.execRunningCount++;
@@ -925,10 +774,6 @@ export class Matterbridge extends EventEmitter {
925
774
  });
926
775
  });
927
776
  }
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
777
  async getGlobalNodeModules() {
933
778
  return new Promise((resolve, reject) => {
934
779
  this.execRunningCount++;
@@ -943,11 +788,6 @@ export class Matterbridge extends EventEmitter {
943
788
  });
944
789
  });
945
790
  }
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
791
  async getMatterbridgeLatestVersion() {
952
792
  this.getLatestVersion('matterbridge')
953
793
  .then(async (matterbridgeLatestVersion) => {
@@ -964,19 +804,8 @@ export class Matterbridge extends EventEmitter {
964
804
  })
965
805
  .catch((error) => {
966
806
  this.log.error(`Error getting Matterbridge latest version: ${error.message}`);
967
- // error.stack && this.log.debug(error.stack);
968
807
  });
969
808
  }
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
809
  async getPluginLatestVersion(plugin) {
981
810
  this.getLatestVersion(plugin.name)
982
811
  .then(async (latestVersion) => {
@@ -988,54 +817,40 @@ export class Matterbridge extends EventEmitter {
988
817
  })
989
818
  .catch((error) => {
990
819
  this.log.error(`Error getting ${plg}${plugin.name}${er} latest version: ${error.message}`);
991
- // error.stack && this.log.debug(error.stack);
992
820
  });
993
821
  }
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
822
  createMatterLogger() {
1000
- const matterLogger = new AnsiLogger({ logName: 'Matter', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: "debug" /* LogLevel.DEBUG */ });
823
+ const matterLogger = new AnsiLogger({ logName: 'Matter', logTimestampFormat: 4, logLevel: "debug" });
1001
824
  return (_level, formattedLog) => {
1002
825
  const logger = formattedLog.slice(44, 44 + 20).trim();
1003
826
  const message = formattedLog.slice(65);
1004
827
  matterLogger.logName = logger;
1005
828
  switch (_level) {
1006
829
  case MatterLogLevel.DEBUG:
1007
- matterLogger.log("debug" /* LogLevel.DEBUG */, message);
830
+ matterLogger.log("debug", message);
1008
831
  break;
1009
832
  case MatterLogLevel.INFO:
1010
- matterLogger.log("info" /* LogLevel.INFO */, message);
833
+ matterLogger.log("info", message);
1011
834
  break;
1012
835
  case MatterLogLevel.NOTICE:
1013
- matterLogger.log("notice" /* LogLevel.NOTICE */, message);
836
+ matterLogger.log("notice", message);
1014
837
  break;
1015
838
  case MatterLogLevel.WARN:
1016
- matterLogger.log("warn" /* LogLevel.WARN */, message);
839
+ matterLogger.log("warn", message);
1017
840
  break;
1018
841
  case MatterLogLevel.ERROR:
1019
- matterLogger.log("error" /* LogLevel.ERROR */, message);
842
+ matterLogger.log("error", message);
1020
843
  break;
1021
844
  case MatterLogLevel.FATAL:
1022
- matterLogger.log("fatal" /* LogLevel.FATAL */, message);
845
+ matterLogger.log("fatal", message);
1023
846
  break;
1024
847
  default:
1025
- matterLogger.log("debug" /* LogLevel.DEBUG */, message);
848
+ matterLogger.log("debug", message);
1026
849
  break;
1027
850
  }
1028
851
  };
1029
852
  }
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
853
  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
854
  let fileSize = 0;
1040
855
  if (unlink) {
1041
856
  try {
@@ -1084,83 +899,53 @@ export class Matterbridge extends EventEmitter {
1084
899
  }
1085
900
  };
1086
901
  }
1087
- /**
1088
- * Update matterbridge and cleanup.
1089
- */
1090
902
  async updateProcess() {
1091
903
  await this.cleanup('updating...', false);
1092
904
  }
1093
- /**
1094
- * Restarts the process by spawning a new process and exiting the current process.
1095
- */
1096
905
  async restartProcess() {
1097
906
  await this.cleanup('restarting...', true);
1098
907
  }
1099
- /**
1100
- * Shut down the process by exiting the current process.
1101
- */
1102
908
  async shutdownProcess() {
1103
909
  await this.cleanup('shutting down...', false);
1104
910
  }
1105
- /**
1106
- * Shut down the process and reset.
1107
- */
1108
911
  async unregisterAndShutdownProcess() {
1109
912
  this.log.info('Unregistering all devices and shutting down...');
1110
- for (const plugin of this.plugins /* .filter((plugin) => plugin.enabled && !plugin.error))*/) {
913
+ for (const plugin of this.plugins) {
1111
914
  await this.removeAllBridgedDevices(plugin.name);
1112
915
  }
1113
916
  await this.cleanup('unregistered all devices and shutting down...', false);
1114
917
  }
1115
- /**
1116
- * Shut down the process and reset.
1117
- */
1118
918
  async shutdownProcessAndReset() {
1119
919
  await this.cleanup('shutting down with reset...', false);
1120
920
  }
1121
- /**
1122
- * Shut down the process and factory reset.
1123
- */
1124
921
  async shutdownProcessAndFactoryReset() {
1125
922
  await this.cleanup('shutting down with factory reset...', false);
1126
923
  }
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
924
  async cleanup(message, restart = false) {
1134
925
  if (this.initialized && !this.hasCleanupStarted) {
1135
926
  this.hasCleanupStarted = true;
1136
927
  this.log.info(message);
1137
- // Deregisters the process handlers
1138
928
  this.deregisterProcesslHandlers();
1139
- // Clear the start matter interval
1140
929
  if (this.startMatterInterval) {
1141
930
  clearInterval(this.startMatterInterval);
1142
931
  this.startMatterInterval = undefined;
1143
932
  this.log.debug('Start matter interval cleared');
1144
933
  }
1145
- // Clear the check update interval
1146
934
  if (this.checkUpdateInterval) {
1147
935
  clearInterval(this.checkUpdateInterval);
1148
936
  this.checkUpdateInterval = undefined;
1149
937
  this.log.debug('Check update interval cleared');
1150
938
  }
1151
- // Clear the configure timeout
1152
939
  if (this.configureTimeout) {
1153
940
  clearTimeout(this.configureTimeout);
1154
941
  this.configureTimeout = undefined;
1155
942
  this.log.debug('Matterbridge configure timeout cleared');
1156
943
  }
1157
- // Clear the reachability timeout
1158
944
  if (this.reachabilityTimeout) {
1159
945
  clearTimeout(this.reachabilityTimeout);
1160
946
  this.reachabilityTimeout = undefined;
1161
947
  this.log.debug('Matterbridge reachability timeout cleared');
1162
948
  }
1163
- // Calling the shutdown method of each plugin and clear the reachability timeout
1164
949
  for (const plugin of this.plugins) {
1165
950
  if (!plugin.enabled || plugin.error)
1166
951
  continue;
@@ -1171,29 +956,24 @@ export class Matterbridge extends EventEmitter {
1171
956
  this.log.debug(`Plugin ${plg}${plugin.name}${db} reachability timeout cleared`);
1172
957
  }
1173
958
  }
1174
- // Close the http server
1175
959
  if (this.httpServer) {
1176
960
  this.httpServer.close();
1177
961
  this.httpServer.removeAllListeners();
1178
962
  this.httpServer = undefined;
1179
963
  this.log.debug('Frontend http server closed successfully');
1180
964
  }
1181
- // Close the https server
1182
965
  if (this.httpsServer) {
1183
966
  this.httpsServer.close();
1184
967
  this.httpsServer.removeAllListeners();
1185
968
  this.httpsServer = undefined;
1186
969
  this.log.debug('Frontend https server closed successfully');
1187
970
  }
1188
- // Remove listeners from the express app
1189
971
  if (this.expressApp) {
1190
972
  this.expressApp.removeAllListeners();
1191
973
  this.expressApp = undefined;
1192
974
  this.log.debug('Frontend app closed successfully');
1193
975
  }
1194
- // Close the WebSocket server
1195
976
  if (this.webSocketServer) {
1196
- // Close all active connections
1197
977
  this.webSocketServer.clients.forEach((client) => {
1198
978
  if (client.readyState === WebSocket.OPEN) {
1199
979
  client.close();
@@ -1209,35 +989,26 @@ export class Matterbridge extends EventEmitter {
1209
989
  });
1210
990
  this.webSocketServer = undefined;
1211
991
  }
1212
- // Closing matter
1213
992
  await this.stopMatterServer();
1214
- // Closing matter storage
1215
993
  await this.stopMatterStorage();
1216
- // Remove the matterfilelogger
1217
994
  try {
1218
995
  Logger.removeLogger('matterfilelogger');
1219
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1220
996
  }
1221
997
  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
998
  }
1224
- // Serialize registeredDevices
1225
999
  if (this.nodeStorage && this.nodeContext) {
1226
1000
  this.log.info('Saving registered devices...');
1227
1001
  const serializedRegisteredDevices = [];
1228
1002
  this.devices.forEach(async (device) => {
1229
1003
  const serializedMatterbridgeDevice = device.serialize();
1230
- // this.log.info(`- ${serializedMatterbridgeDevice.deviceName}${rs}\n`, serializedMatterbridgeDevice);
1231
1004
  if (serializedMatterbridgeDevice)
1232
1005
  serializedRegisteredDevices.push(serializedMatterbridgeDevice);
1233
1006
  });
1234
1007
  await this.nodeContext.set('devices', serializedRegisteredDevices);
1235
1008
  this.log.info(`Saved registered devices (${serializedRegisteredDevices?.length})`);
1236
- // Clear nodeContext and nodeStorage (they just need 1000ms to write the data to disk)
1237
1009
  this.log.debug(`Closing node storage context for ${plg}Matterbridge${db}...`);
1238
1010
  await this.nodeContext.close();
1239
1011
  this.nodeContext = undefined;
1240
- // Clear nodeContext for each plugin (they just need 1000ms to write the data to disk)
1241
1012
  for (const plugin of this.plugins) {
1242
1013
  if (plugin.nodeContext) {
1243
1014
  this.log.debug(`Closing node storage context for plugin ${plg}${plugin.name}${db}...`);
@@ -1268,16 +1039,13 @@ export class Matterbridge extends EventEmitter {
1268
1039
  }
1269
1040
  else {
1270
1041
  if (message === 'shutting down with reset...') {
1271
- // Delete matter storage file
1272
1042
  this.log.info('Resetting Matterbridge commissioning information...');
1273
1043
  await fs.unlink(path.join(this.matterbridgeDirectory, this.matterStorageName));
1274
1044
  this.log.info('Reset done! Remove all paired devices from the controllers.');
1275
1045
  }
1276
1046
  if (message === 'shutting down with factory reset...') {
1277
- // Delete matter storage file
1278
1047
  this.log.info('Resetting Matterbridge commissioning information...');
1279
1048
  await fs.unlink(path.join(this.matterbridgeDirectory, this.matterStorageName));
1280
- // Delete node storage directory with its subdirectories
1281
1049
  this.log.info('Resetting Matterbridge storage...');
1282
1050
  await fs.rm(path.join(this.matterbridgeDirectory, this.nodeStorageName), { recursive: true });
1283
1051
  this.log.info('Factory reset done! Remove all paired devices from the controllers.');
@@ -1290,33 +1058,19 @@ export class Matterbridge extends EventEmitter {
1290
1058
  this.initialized = false;
1291
1059
  }
1292
1060
  }
1293
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1294
1061
  async addBridgedEndpoint(pluginName, device) {
1295
- // Nothing to do here
1296
1062
  }
1297
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1298
1063
  async removeBridgedEndpoint(pluginName, device) {
1299
- // Nothing to do here
1300
1064
  }
1301
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1302
1065
  async removeAllBridgedEndpoints(pluginName) {
1303
- // Nothing to do here
1304
1066
  }
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
1067
  async addBridgedDevice(pluginName, device) {
1312
1068
  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
1069
  const plugin = this.plugins.get(pluginName);
1315
1070
  if (!plugin) {
1316
1071
  this.log.error(`Error adding bridged device ${dev}${device.deviceName}${er} (${zb}${device.name}${er}) plugin ${plg}${pluginName}${er} not found`);
1317
1072
  return;
1318
1073
  }
1319
- // Register and add the device to matterbridge aggregator in bridge mode
1320
1074
  if (this.bridgeMode === 'bridge') {
1321
1075
  if (!this.matterAggregator) {
1322
1076
  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 +1078,8 @@ export class Matterbridge extends EventEmitter {
1324
1078
  }
1325
1079
  this.matterAggregator.addBridgedDevice(device);
1326
1080
  }
1327
- // The first time create the commissioning server and the aggregator for DynamicPlatform
1328
- // Register and add the device in childbridge mode
1329
1081
  if (this.bridgeMode === 'childbridge') {
1330
1082
  if (plugin.type === 'AccessoryPlatform') {
1331
- // Check if the plugin is locked with the commissioning server
1332
1083
  if (!plugin.locked) {
1333
1084
  plugin.locked = true;
1334
1085
  plugin.storageContext = await this.importCommissioningServerContext(plugin.name, device);
@@ -1342,7 +1093,6 @@ export class Matterbridge extends EventEmitter {
1342
1093
  }
1343
1094
  }
1344
1095
  if (plugin.type === 'DynamicPlatform') {
1345
- // Check if the plugin is locked with the commissioning server and the aggregator
1346
1096
  if (!plugin.locked) {
1347
1097
  plugin.locked = true;
1348
1098
  this.log.debug(`Creating commissioning server context for ${plg}${plugin.name}${db}`);
@@ -1363,25 +1113,16 @@ export class Matterbridge extends EventEmitter {
1363
1113
  plugin.registeredDevices++;
1364
1114
  if (plugin.addedDevices !== undefined)
1365
1115
  plugin.addedDevices++;
1366
- // Add the device to the DeviceManager
1367
1116
  this.devices.set(device);
1368
1117
  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
1118
  }
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
1119
  async removeBridgedDevice(pluginName, device) {
1377
1120
  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
1121
  const plugin = this.plugins.get(pluginName);
1380
1122
  if (!plugin) {
1381
1123
  this.log.error(`Error removing bridged device ${dev}${device.deviceName}${er} (${zb}${device.name}${er}) for plugin ${plg}${pluginName}${er}: plugin not found`);
1382
1124
  return;
1383
1125
  }
1384
- // Remove the device from matterbridge aggregator in bridge mode
1385
1126
  if (this.bridgeMode === 'bridge') {
1386
1127
  if (!this.matterAggregator) {
1387
1128
  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 +1132,6 @@ export class Matterbridge extends EventEmitter {
1391
1132
  device.setBridgedDeviceReachability(false);
1392
1133
  device.getClusterServerById(BridgedDeviceBasicInformation.Cluster.id)?.triggerReachableChangedEvent({ reachableNewValue: false });
1393
1134
  }
1394
- // device.getClusterServerById(BridgedDeviceBasicInformation.Cluster.id)?.triggerShutDownEvent({});
1395
- // device.getClusterServerById(BridgedDeviceBasicInformation.Cluster.id)?.triggerLeaveEvent({});
1396
1135
  this.matterAggregator?.removeBridgedDevice(device);
1397
1136
  this.log.info(`Removed bridged device(${plugin.registeredDevices}/${plugin.addedDevices}) ${dev}${device.deviceName}${nf} (${zb}${device.name}${nf}) for plugin ${plg}${pluginName}${nf}`);
1398
1137
  if (plugin.registeredDevices !== undefined)
@@ -1400,7 +1139,6 @@ export class Matterbridge extends EventEmitter {
1400
1139
  if (plugin.addedDevices !== undefined)
1401
1140
  plugin.addedDevices--;
1402
1141
  }
1403
- // Remove the device in childbridge mode
1404
1142
  if (this.bridgeMode === 'childbridge') {
1405
1143
  if (plugin.type === 'AccessoryPlatform') {
1406
1144
  if (!plugin.commissioningServer) {
@@ -1424,22 +1162,14 @@ export class Matterbridge extends EventEmitter {
1424
1162
  plugin.registeredDevices--;
1425
1163
  if (plugin.addedDevices !== undefined)
1426
1164
  plugin.addedDevices--;
1427
- // Remove the commissioning server
1428
1165
  if (plugin.registeredDevices === 0 && plugin.addedDevices === 0 && plugin.commissioningServer) {
1429
1166
  this.matterServer?.removeCommissioningServer(plugin.commissioningServer);
1430
1167
  plugin.commissioningServer = undefined;
1431
1168
  this.log.info(`Removed commissioning server for plugin ${plg}${pluginName}${nf}`);
1432
1169
  }
1433
1170
  }
1434
- // Remove the device from the DeviceManager
1435
1171
  this.devices.remove(device);
1436
1172
  }
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
1173
  async removeAllBridgedDevices(pluginName) {
1444
1174
  this.log.debug(`Removing all bridged devices for plugin ${plg}${pluginName}${db}`);
1445
1175
  this.devices.forEach(async (device) => {
@@ -1448,13 +1178,7 @@ export class Matterbridge extends EventEmitter {
1448
1178
  }
1449
1179
  });
1450
1180
  }
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
1181
  async startBridge() {
1457
- // Plugins are configured by a timer when matter server is started and plugin.configured is set to true
1458
1182
  if (!this.storageManager)
1459
1183
  throw new Error('No storage manager initialized');
1460
1184
  if (!this.matterbridgeContext)
@@ -1473,7 +1197,6 @@ export class Matterbridge extends EventEmitter {
1473
1197
  let failCount = 0;
1474
1198
  this.startMatterInterval = setInterval(async () => {
1475
1199
  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
1200
  if (!plugin.enabled)
1478
1201
  continue;
1479
1202
  if (plugin.error) {
@@ -1498,18 +1221,15 @@ export class Matterbridge extends EventEmitter {
1498
1221
  clearInterval(this.startMatterInterval);
1499
1222
  this.startMatterInterval = undefined;
1500
1223
  this.log.debug('Cleared startMatterInterval interval for Matterbridge');
1501
- // Start the Matter server
1502
1224
  await this.startMatterServer();
1503
1225
  this.log.notice('Matter server started');
1504
- // Show the QR code for commissioning or log the already commissioned message
1505
1226
  await this.showCommissioningQRCode(this.commissioningServer, this.matterbridgeContext, this.nodeContext, 'Matterbridge');
1506
- // Configure the plugins
1507
1227
  this.configureTimeout = setTimeout(async () => {
1508
1228
  for (const plugin of this.plugins) {
1509
1229
  if (!plugin.enabled || !plugin.loaded || !plugin.started || plugin.error)
1510
1230
  continue;
1511
1231
  try {
1512
- await this.plugins.configure(plugin); // TODO No await do it in parallel
1232
+ await this.plugins.configure(plugin);
1513
1233
  }
1514
1234
  catch (error) {
1515
1235
  plugin.error = true;
@@ -1518,7 +1238,6 @@ export class Matterbridge extends EventEmitter {
1518
1238
  }
1519
1239
  this.wssSendRefreshRequired();
1520
1240
  }, 30 * 1000);
1521
- // Setting reachability to true
1522
1241
  this.reachabilityTimeout = setTimeout(() => {
1523
1242
  this.log.info(`Setting reachability to true for ${plg}Matterbridge${db}`);
1524
1243
  if (this.commissioningServer)
@@ -1528,14 +1247,7 @@ export class Matterbridge extends EventEmitter {
1528
1247
  }, 60 * 1000);
1529
1248
  }, 1000);
1530
1249
  }
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
1250
  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
1251
  if (!this.storageManager)
1540
1252
  throw new Error('No storage manager initialized');
1541
1253
  this.matterServer = this.createMatterServer(this.storageManager);
@@ -1545,7 +1257,6 @@ export class Matterbridge extends EventEmitter {
1545
1257
  this.startMatterInterval = setInterval(async () => {
1546
1258
  let allStarted = true;
1547
1259
  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
1260
  if (!plugin.enabled)
1550
1261
  continue;
1551
1262
  if (plugin.error) {
@@ -1573,16 +1284,14 @@ export class Matterbridge extends EventEmitter {
1573
1284
  clearInterval(this.startMatterInterval);
1574
1285
  this.startMatterInterval = undefined;
1575
1286
  this.log.debug('Cleared startMatterInterval interval in childbridge mode');
1576
- // Start the Matter server
1577
1287
  await this.startMatterServer();
1578
1288
  this.log.notice('Matter server started');
1579
- // Configure the plugins
1580
1289
  this.configureTimeout = setTimeout(async () => {
1581
1290
  for (const plugin of this.plugins) {
1582
1291
  if (!plugin.enabled || !plugin.loaded || !plugin.started || plugin.error)
1583
1292
  continue;
1584
1293
  try {
1585
- await this.plugins.configure(plugin); // TODO No await do it in parallel
1294
+ await this.plugins.configure(plugin);
1586
1295
  }
1587
1296
  catch (error) {
1588
1297
  plugin.error = true;
@@ -1611,7 +1320,6 @@ export class Matterbridge extends EventEmitter {
1611
1320
  continue;
1612
1321
  }
1613
1322
  await this.showCommissioningQRCode(plugin.commissioningServer, plugin.storageContext, plugin.nodeContext, plugin.name);
1614
- // Setting reachability to true
1615
1323
  plugin.reachabilityTimeout = setTimeout(() => {
1616
1324
  this.log.info(`Setting reachability to true for ${plg}${plugin.name}${db}`);
1617
1325
  if (plugin.commissioningServer)
@@ -1624,11 +1332,6 @@ export class Matterbridge extends EventEmitter {
1624
1332
  }
1625
1333
  }, 1000);
1626
1334
  }
1627
- /**
1628
- * Starts the Matterbridge controller.
1629
- * @private
1630
- * @returns {Promise<void>} A promise that resolves when the Matterbridge is started.
1631
- */
1632
1335
  async startController() {
1633
1336
  if (!this.storageManager) {
1634
1337
  this.log.error('No storage manager initialized');
@@ -1691,7 +1394,7 @@ export class Matterbridge extends EventEmitter {
1691
1394
  const nodeId = await this.commissioningController.commissionNode(options);
1692
1395
  this.log.info(`Commissioning successfully done with nodeId: ${nodeId}`);
1693
1396
  this.log.info('ActiveSessionInformation:', this.commissioningController.getActiveSessionInformation());
1694
- } // (hasParameter('pairingcode'))
1397
+ }
1695
1398
  if (hasParameter('unpairall')) {
1696
1399
  this.log.info('***Commissioning controller unpairing all nodes...');
1697
1400
  const nodeIds = this.commissioningController.getCommissionedNodes();
@@ -1702,8 +1405,6 @@ export class Matterbridge extends EventEmitter {
1702
1405
  return;
1703
1406
  }
1704
1407
  if (hasParameter('discover')) {
1705
- // const discover = await this.commissioningController.discoverCommissionableDevices({ productId: 0x8000, deviceType: 0xfff1 });
1706
- // console.log(discover);
1707
1408
  }
1708
1409
  if (!this.commissioningController.isCommissioned()) {
1709
1410
  this.log.info('***Commissioning controller is not commissioned: use matterbridge -controller -pairingcode [pairingcode] to commission a device');
@@ -1744,12 +1445,10 @@ export class Matterbridge extends EventEmitter {
1744
1445
  },
1745
1446
  });
1746
1447
  node.logStructure();
1747
- // Get the interaction client
1748
1448
  this.log.info('Getting the interaction client');
1749
1449
  const interactionClient = await node.getInteractionClient();
1750
1450
  let cluster;
1751
1451
  let attributes;
1752
- // Log BasicInformationCluster
1753
1452
  cluster = BasicInformationCluster;
1754
1453
  attributes = await interactionClient.getMultipleAttributes({
1755
1454
  attributes: [{ clusterId: cluster.id }],
@@ -1759,7 +1458,6 @@ export class Matterbridge extends EventEmitter {
1759
1458
  attributes.forEach((attribute) => {
1760
1459
  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
1460
  });
1762
- // Log PowerSourceCluster
1763
1461
  cluster = PowerSourceCluster;
1764
1462
  attributes = await interactionClient.getMultipleAttributes({
1765
1463
  attributes: [{ clusterId: cluster.id }],
@@ -1769,7 +1467,6 @@ export class Matterbridge extends EventEmitter {
1769
1467
  attributes.forEach((attribute) => {
1770
1468
  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
1469
  });
1772
- // Log ThreadNetworkDiagnostics
1773
1470
  cluster = ThreadNetworkDiagnosticsCluster;
1774
1471
  attributes = await interactionClient.getMultipleAttributes({
1775
1472
  attributes: [{ clusterId: cluster.id }],
@@ -1779,7 +1476,6 @@ export class Matterbridge extends EventEmitter {
1779
1476
  attributes.forEach((attribute) => {
1780
1477
  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
1478
  });
1782
- // Log SwitchCluster
1783
1479
  cluster = SwitchCluster;
1784
1480
  attributes = await interactionClient.getMultipleAttributes({
1785
1481
  attributes: [{ clusterId: cluster.id }],
@@ -1800,15 +1496,6 @@ export class Matterbridge extends EventEmitter {
1800
1496
  this.log.info('Subscribed to all attributes and events');
1801
1497
  }
1802
1498
  }
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
1499
  async startMatterStorage(storageType, storageName) {
1813
1500
  this.log.debug(`Starting matter ${storageType} storage ${CYAN}${storageName}${db}`);
1814
1501
  if (storageType === 'disk') {
@@ -1854,12 +1541,6 @@ export class Matterbridge extends EventEmitter {
1854
1541
  this.log.debug(`Creating commissioning server context for ${plg}Matterbridge${db}`);
1855
1542
  this.matterbridgeContext = await this.createCommissioningServerContext('Matterbridge', 'Matterbridge', DeviceTypes.AGGREGATOR.code, 0xfff1, 'Matterbridge', 0x8000, 'Matterbridge aggregator');
1856
1543
  }
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
1544
  async backupMatterStorage(storageName, backupName) {
1864
1545
  try {
1865
1546
  this.log.debug(`Making backup copy of ${storageName}`);
@@ -1880,12 +1561,6 @@ export class Matterbridge extends EventEmitter {
1880
1561
  }
1881
1562
  }
1882
1563
  }
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
1564
  async restoreMatterStorage(backupName, storageName) {
1890
1565
  try {
1891
1566
  this.log.notice(`Restoring the backup copy of ${storageName}`);
@@ -1906,10 +1581,6 @@ export class Matterbridge extends EventEmitter {
1906
1581
  }
1907
1582
  }
1908
1583
  }
1909
- /**
1910
- * Stops the matter storage.
1911
- * @returns {Promise<void>} A promise that resolves when the storage is stopped.
1912
- */
1913
1584
  async stopMatterStorage() {
1914
1585
  this.log.debug('Stopping storage');
1915
1586
  await this.storageManager?.close();
@@ -1918,14 +1589,8 @@ export class Matterbridge extends EventEmitter {
1918
1589
  this.matterbridgeContext = undefined;
1919
1590
  this.mattercontrollerContext = undefined;
1920
1591
  }
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
1592
  createMatterServer(storageManager) {
1927
1593
  this.log.debug('Creating matter server');
1928
- // Validate mdnsInterface
1929
1594
  if (this.mdnsInterface) {
1930
1595
  const networkInterfaces = os.networkInterfaces();
1931
1596
  const availableInterfaces = Object.keys(networkInterfaces);
@@ -1941,10 +1606,6 @@ export class Matterbridge extends EventEmitter {
1941
1606
  this.log.debug(`Created matter server with mdnsInterface: ${this.mdnsInterface ?? 'all available interfaces'}`);
1942
1607
  return matterServer;
1943
1608
  }
1944
- /**
1945
- * Starts the Matter server.
1946
- * If the Matter server is not initialized, it logs an error and performs cleanup.
1947
- */
1948
1609
  async startMatterServer() {
1949
1610
  if (!this.matterServer) {
1950
1611
  this.log.error('No matter server initialized');
@@ -1954,11 +1615,7 @@ export class Matterbridge extends EventEmitter {
1954
1615
  this.log.debug('Starting matter server...');
1955
1616
  await this.matterServer.start();
1956
1617
  this.log.debug('Started matter server');
1957
- // this.commissioningServer?.getRootEndpoint() && logEndpoint(this.commissioningServer?.getRootEndpoint());
1958
1618
  }
1959
- /**
1960
- * Stops the Matter server, commissioningServer and commissioningController.
1961
- */
1962
1619
  async stopMatterServer() {
1963
1620
  this.log.debug('Stopping matter commissioningServer');
1964
1621
  await this.commissioningServer?.close();
@@ -1972,35 +1629,23 @@ export class Matterbridge extends EventEmitter {
1972
1629
  this.matterAggregator = undefined;
1973
1630
  this.matterServer = undefined;
1974
1631
  }
1975
- /**
1976
- * Creates a Matter Aggregator.
1977
- * @param {StorageContext} context - The storage context.
1978
- * @returns {Aggregator} - The created Matter Aggregator.
1979
- */
1980
1632
  async createMatterAggregator(context, pluginName) {
1981
1633
  this.log.debug(`Creating matter aggregator for ${plg}${pluginName}${db}`);
1982
1634
  const matterAggregator = new Aggregator();
1983
1635
  return matterAggregator;
1984
1636
  }
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
1637
  async createCommisioningServer(context, pluginName) {
1993
1638
  this.log.debug(`Creating matter commissioning server for plugin ${plg}${pluginName}${db}`);
1994
1639
  const deviceName = await context.get('deviceName');
1995
1640
  const deviceType = await context.get('deviceType');
1996
1641
  const vendorId = await context.get('vendorId');
1997
- const vendorName = await context.get('vendorName'); // Home app = Manufacturer
1642
+ const vendorName = await context.get('vendorName');
1998
1643
  const productId = await context.get('productId');
1999
- const productName = await context.get('productName'); // Home app = Model
1644
+ const productName = await context.get('productName');
2000
1645
  const serialNumber = await context.get('serialNumber');
2001
1646
  const uniqueId = await context.get('uniqueId');
2002
1647
  const softwareVersion = await context.get('softwareVersion', 1);
2003
- const softwareVersionString = await context.get('softwareVersionString', '1.0.0'); // Home app = Firmware Revision
1648
+ const softwareVersionString = await context.get('softwareVersionString', '1.0.0');
2004
1649
  const hardwareVersion = await context.get('hardwareVersion', 1);
2005
1650
  const hardwareVersionString = await context.get('hardwareVersionString', '1.0.0');
2006
1651
  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 +1653,6 @@ export class Matterbridge extends EventEmitter {
2008
1653
  this.log.debug(`Creating matter commissioning server for plugin ${plg}${pluginName}${db} with softwareVersion ${softwareVersion} softwareVersionString ${softwareVersionString}`);
2009
1654
  this.log.debug(`Creating matter commissioning server for plugin ${plg}${pluginName}${db} with hardwareVersion ${hardwareVersion} hardwareVersionString ${hardwareVersionString}`);
2010
1655
  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
1656
  if (this.ipv4address) {
2013
1657
  const networkInterfaces = os.networkInterfaces();
2014
1658
  const availableAddresses = Object.values(networkInterfaces)
@@ -2023,7 +1667,6 @@ export class Matterbridge extends EventEmitter {
2023
1667
  this.log.info(`Using ipv4address '${this.ipv4address}' for the Matter commissioning server.`);
2024
1668
  }
2025
1669
  }
2026
- // Validate ipv6address
2027
1670
  if (this.ipv6address) {
2028
1671
  const networkInterfaces = os.networkInterfaces();
2029
1672
  const availableAddresses = Object.values(networkInterfaces)
@@ -2054,7 +1697,7 @@ export class Matterbridge extends EventEmitter {
2054
1697
  nodeLabel: productName,
2055
1698
  productLabel: productName,
2056
1699
  softwareVersion,
2057
- softwareVersionString, // Home app = Firmware Revision
1700
+ softwareVersionString,
2058
1701
  hardwareVersion,
2059
1702
  hardwareVersionString,
2060
1703
  uniqueId,
@@ -2150,24 +1793,6 @@ export class Matterbridge extends EventEmitter {
2150
1793
  commissioningServer.addCommandHandler('testEventTrigger', async ({ request: { enableKey, eventTrigger } }) => this.log.info(`testEventTrigger called on GeneralDiagnostic cluster: ${enableKey} ${eventTrigger}`));
2151
1794
  return commissioningServer;
2152
1795
  }
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
1796
  async createCommissioningServerContext(pluginName, deviceName, deviceType, vendorId, vendorName, productId, productName) {
2172
1797
  if (!this.storageManager)
2173
1798
  throw new Error('No storage manager initialized');
@@ -2195,13 +1820,6 @@ export class Matterbridge extends EventEmitter {
2195
1820
  this.log.debug(`- hardwareVersion: ${await storageContext.get('hardwareVersion')} hardwareVersionString: ${await storageContext.get('hardwareVersionString')}`);
2196
1821
  return storageContext;
2197
1822
  }
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
1823
  async importCommissioningServerContext(pluginName, device) {
2206
1824
  this.log.debug(`Importing matter commissioning server storage context from device for ${plg}${pluginName}${db}`);
2207
1825
  const basic = device.getClusterServer(BasicInformationCluster);
@@ -2236,14 +1854,6 @@ export class Matterbridge extends EventEmitter {
2236
1854
  this.log.debug(`- hardwareVersion: ${await storageContext.get('hardwareVersion')} hardwareVersionString: ${await storageContext.get('hardwareVersionString')}`);
2237
1855
  return storageContext;
2238
1856
  }
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
1857
  async showCommissioningQRCode(commissioningServer, storageContext, nodeContext, pluginName) {
2248
1858
  if (!commissioningServer || !storageContext || !nodeContext || !pluginName) {
2249
1859
  this.log.error(`showCommissioningQRCode error: commissioningServer: ${!commissioningServer} storageContext: ${!storageContext} nodeContext: ${!nodeContext} pluginName: ${pluginName}`);
@@ -2254,8 +1864,7 @@ export class Matterbridge extends EventEmitter {
2254
1864
  const { qrPairingCode, manualPairingCode } = commissioningServer.getPairingCode();
2255
1865
  const QrCode = new QrCodeSchema();
2256
1866
  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 */)
1867
+ if (this.log.logLevel === "debug" || this.log.logLevel === "info")
2259
1868
  console.log(`${QrCode.encode(qrPairingCode)}\n`);
2260
1869
  this.log.info(`${plg}${pluginName}${nf} \n\nqrPairingCode: ${qrPairingCode} \n\nManual pairing code: ${manualPairingCode}\n`);
2261
1870
  if (pluginName === 'Matterbridge') {
@@ -2302,12 +1911,6 @@ export class Matterbridge extends EventEmitter {
2302
1911
  }
2303
1912
  this.wssSendRefreshRequired();
2304
1913
  }
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
1914
  sanitizeFabricInformations(fabricInfo) {
2312
1915
  return fabricInfo.map((info) => {
2313
1916
  return {
@@ -2321,12 +1924,6 @@ export class Matterbridge extends EventEmitter {
2321
1924
  };
2322
1925
  });
2323
1926
  }
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
1927
  sanitizeSessionInformation(sessionInfo) {
2331
1928
  return sessionInfo
2332
1929
  .filter((session) => session.isPeerActive)
@@ -2354,12 +1951,6 @@ export class Matterbridge extends EventEmitter {
2354
1951
  };
2355
1952
  });
2356
1953
  }
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
1954
  setCommissioningServerReachability(commissioningServer, reachable) {
2364
1955
  const basicInformationCluster = commissioningServer?.getRootClusterServer(BasicInformationCluster);
2365
1956
  if (basicInformationCluster && basicInformationCluster.attributes.reachable !== undefined)
@@ -2367,11 +1958,6 @@ export class Matterbridge extends EventEmitter {
2367
1958
  if (basicInformationCluster && basicInformationCluster.triggerReachableChangedEvent)
2368
1959
  basicInformationCluster.triggerReachableChangedEvent({ reachableNewValue: reachable });
2369
1960
  }
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
1961
  setAggregatorReachability(matterAggregator, reachable) {
2376
1962
  const basicInformationCluster = matterAggregator.getClusterServer(BasicInformationCluster);
2377
1963
  if (basicInformationCluster && basicInformationCluster.attributes.reachable !== undefined)
@@ -2384,12 +1970,6 @@ export class Matterbridge extends EventEmitter {
2384
1970
  device.getClusterServer(BridgedDeviceBasicInformationCluster)?.triggerReachableChangedEvent({ reachableNewValue: reachable });
2385
1971
  });
2386
1972
  }
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
1973
  setDeviceReachability(device, reachable) {
2394
1974
  const basicInformationCluster = device.getClusterServer(BasicInformationCluster);
2395
1975
  if (basicInformationCluster && basicInformationCluster.attributes.reachable !== undefined)
@@ -2438,10 +2018,6 @@ export class Matterbridge extends EventEmitter {
2438
2018
  }
2439
2019
  return vendorName;
2440
2020
  };
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
2021
  async getBaseRegisteredPlugins() {
2446
2022
  const baseRegisteredPlugins = [];
2447
2023
  for (const plugin of this.plugins) {
@@ -2473,36 +2049,13 @@ export class Matterbridge extends EventEmitter {
2473
2049
  }
2474
2050
  return baseRegisteredPlugins;
2475
2051
  }
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
2052
  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
2053
  const cmdLine = command + ' ' + args.join(' ');
2497
2054
  if (process.platform === 'win32' && command === 'npm') {
2498
- // Must be spawn('cmd.exe', ['/c', 'npm -g install <package>']);
2499
2055
  const argstring = 'npm ' + args.join(' ');
2500
2056
  args.splice(0, args.length, '/c', argstring);
2501
2057
  command = 'cmd.exe';
2502
2058
  }
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
2059
  if (hasParameter('sudo') || (process.platform === 'linux' && command === 'npm' && !hasParameter('docker') && !hasParameter('nosudo'))) {
2507
2060
  args.unshift(command);
2508
2061
  command = 'sudo';
@@ -2560,102 +2113,55 @@ export class Matterbridge extends EventEmitter {
2560
2113
  }
2561
2114
  });
2562
2115
  }
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
2116
  wssSendMessage(level, time, name, message) {
2572
2117
  if (!level || !time || !name || !message)
2573
2118
  return;
2574
- // Remove ANSI escape codes from the message
2575
- // eslint-disable-next-line no-control-regex
2576
2119
  message = message.replace(/\x1B\[[0-9;]*[m|s|u|K]/g, '');
2577
- // Remove leading asterisks from the message
2578
2120
  message = message.replace(/^\*+/, '');
2579
- // Replace all occurrences of \t and \n
2580
2121
  message = message.replace(/[\t\n]/g, '');
2581
- // Remove non-printable characters
2582
- // eslint-disable-next-line no-control-regex
2583
2122
  message = message.replace(/[\x00-\x1F\x7F]/g, '');
2584
- // Replace all occurrences of \" with "
2585
2123
  message = message.replace(/\\"/g, '"');
2586
- // Define the maximum allowed length for continuous characters without a space
2587
2124
  const maxContinuousLength = 100;
2588
2125
  const keepStartLength = 20;
2589
2126
  const keepEndLength = 20;
2590
- // Split the message into words
2591
2127
  message = message
2592
2128
  .split(' ')
2593
2129
  .map((word) => {
2594
- // If the word length exceeds the max continuous length, insert spaces and truncate
2595
2130
  if (word.length > maxContinuousLength) {
2596
2131
  return word.slice(0, keepStartLength) + ' ... ' + word.slice(-keepEndLength);
2597
2132
  }
2598
2133
  return word;
2599
2134
  })
2600
2135
  .join(' ');
2601
- // Send the message to all connected clients
2602
2136
  this.webSocketServer?.clients.forEach((client) => {
2603
2137
  if (client.readyState === WebSocket.OPEN) {
2604
2138
  client.send(JSON.stringify({ id: WS_ID_LOG, src: 'Matterbridge', level, time, name, message }));
2605
2139
  }
2606
2140
  });
2607
2141
  }
2608
- /**
2609
- * Sends a need to refresh WebSocket message to all connected clients.
2610
- *
2611
- */
2612
2142
  wssSendRefreshRequired() {
2613
2143
  this.matterbridgeInformation.refreshRequired = true;
2614
- // Send the message to all connected clients
2615
2144
  this.webSocketServer?.clients.forEach((client) => {
2616
2145
  if (client.readyState === WebSocket.OPEN) {
2617
2146
  client.send(JSON.stringify({ id: WS_ID_REFRESH_NEEDED, src: 'Matterbridge', dst: 'Matterbridge', method: 'refresh_required', params: {} }));
2618
2147
  }
2619
2148
  });
2620
2149
  }
2621
- /**
2622
- * Sends a need to restart WebSocket message to all connected clients.
2623
- *
2624
- */
2625
2150
  wssSendRestartRequired() {
2626
2151
  this.matterbridgeInformation.restartRequired = true;
2627
- // Send the message to all connected clients
2628
2152
  this.webSocketServer?.clients.forEach((client) => {
2629
2153
  if (client.readyState === WebSocket.OPEN) {
2630
2154
  client.send(JSON.stringify({ id: WS_ID_RESTART_NEEDED, src: 'Matterbridge', dst: 'Matterbridge', method: 'restart_required', params: {} }));
2631
2155
  }
2632
2156
  });
2633
2157
  }
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
2158
  async initializeFrontend(port = 8283) {
2640
2159
  let initializeError = false;
2641
2160
  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
2161
  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
2162
  this.expressApp.use(express.static(path.join(this.rootDirectory, 'frontend/build')));
2655
2163
  if (!hasParameter('ssl')) {
2656
- // Create an HTTP server and attach the express app
2657
2164
  this.httpServer = createServer(this.expressApp);
2658
- // Listen on the specified port
2659
2165
  if (hasParameter('ingress')) {
2660
2166
  this.httpServer.listen(port, '0.0.0.0', () => {
2661
2167
  this.log.info(`The frontend http server is listening on ${UNDERLINE}http://0.0.0.0:${port}${UNDERLINEOFF}${rs}`);
@@ -2669,7 +2175,6 @@ export class Matterbridge extends EventEmitter {
2669
2175
  this.log.info(`The frontend http server is listening on ${UNDERLINE}http://[${this.systemInformation.ipv6Address}]:${port}${UNDERLINEOFF}${rs}`);
2670
2176
  });
2671
2177
  }
2672
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
2673
2178
  this.httpServer.on('error', (error) => {
2674
2179
  this.log.error(`Frontend http server error listening on ${port}`);
2675
2180
  switch (error.code) {
@@ -2685,7 +2190,6 @@ export class Matterbridge extends EventEmitter {
2685
2190
  });
2686
2191
  }
2687
2192
  else {
2688
- // Load the SSL certificate, the private key and optionally the CA certificate
2689
2193
  let cert;
2690
2194
  try {
2691
2195
  cert = await fs.readFile(path.join(this.matterbridgeDirectory, 'certs/cert.pem'), 'utf8');
@@ -2713,9 +2217,7 @@ export class Matterbridge extends EventEmitter {
2713
2217
  this.log.info(`CA certificate file ${path.join(this.matterbridgeDirectory, 'certs/ca.pem')} not loaded: ${error}`);
2714
2218
  }
2715
2219
  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
2220
  this.httpsServer = https.createServer(serverOptions, this.expressApp);
2718
- // Listen on the specified port
2719
2221
  if (hasParameter('ingress')) {
2720
2222
  this.httpsServer.listen(port, '0.0.0.0', () => {
2721
2223
  this.log.info(`The frontend https server is listening on ${UNDERLINE}https://0.0.0.0:${port}${UNDERLINEOFF}${rs}`);
@@ -2729,7 +2231,6 @@ export class Matterbridge extends EventEmitter {
2729
2231
  this.log.info(`The frontend https server is listening on ${UNDERLINE}https://[${this.systemInformation.ipv6Address}]:${port}${UNDERLINEOFF}${rs}`);
2730
2232
  });
2731
2233
  }
2732
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
2733
2234
  this.httpsServer.on('error', (error) => {
2734
2235
  this.log.error(`Frontend https server error listening on ${port}`);
2735
2236
  switch (error.code) {
@@ -2746,13 +2247,12 @@ export class Matterbridge extends EventEmitter {
2746
2247
  }
2747
2248
  if (initializeError)
2748
2249
  return;
2749
- // Createe a WebSocket server and attach it to the http or https server
2750
2250
  const wssPort = port;
2751
2251
  const wssHost = hasParameter('ssl') ? `wss://${this.systemInformation.ipv4Address}:${wssPort}` : `ws://${this.systemInformation.ipv4Address}:${wssPort}`;
2752
2252
  this.webSocketServer = new WebSocketServer(hasParameter('ssl') ? { server: this.httpsServer } : { server: this.httpServer });
2753
2253
  this.webSocketServer.on('connection', (ws, request) => {
2754
2254
  const clientIp = request.socket.remoteAddress;
2755
- AnsiLogger.setGlobalCallback(this.wssSendMessage.bind(this), "debug" /* LogLevel.DEBUG */);
2255
+ AnsiLogger.setGlobalCallback(this.wssSendMessage.bind(this), "debug");
2756
2256
  this.log.info(`WebSocketServer client "${clientIp}" connected to Matterbridge`);
2757
2257
  ws.on('message', (message) => {
2758
2258
  this.log.debug(`WebSocket client message: ${message}`);
@@ -2785,7 +2285,6 @@ export class Matterbridge extends EventEmitter {
2785
2285
  this.webSocketServer.on('error', (ws, error) => {
2786
2286
  this.log.error(`WebSocketServer error: ${error}`);
2787
2287
  });
2788
- // Endpoint to validate login code
2789
2288
  this.expressApp.post('/api/login', express.json(), async (req, res) => {
2790
2289
  const { password } = req.body;
2791
2290
  this.log.debug('The frontend sent /api/login', password);
@@ -2804,14 +2303,12 @@ export class Matterbridge extends EventEmitter {
2804
2303
  this.log.warn('/api/login error wrong password');
2805
2304
  res.json({ valid: false });
2806
2305
  }
2807
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
2808
2306
  }
2809
2307
  catch (error) {
2810
2308
  this.log.error('/api/login error getting password');
2811
2309
  res.json({ valid: false });
2812
2310
  }
2813
2311
  });
2814
- // Endpoint to provide settings
2815
2312
  this.expressApp.get('/api/settings', express.json(), async (req, res) => {
2816
2313
  this.log.debug('The frontend sent /api/settings');
2817
2314
  this.matterbridgeInformation.bridgeMode = this.bridgeMode;
@@ -2832,17 +2329,13 @@ export class Matterbridge extends EventEmitter {
2832
2329
  this.matterbridgeInformation.matterbridgeSessionInformations = Array.from(this.matterbridgeSessionInformations.values());
2833
2330
  this.matterbridgeInformation.profile = this.profile;
2834
2331
  const response = { wssHost, ssl: hasParameter('ssl'), systemInformation: this.systemInformation, matterbridgeInformation: this.matterbridgeInformation };
2835
- // this.log.debug('Response:', debugStringify(response));
2836
2332
  res.json(response);
2837
2333
  });
2838
- // Endpoint to provide plugins
2839
2334
  this.expressApp.get('/api/plugins', async (req, res) => {
2840
2335
  this.log.debug('The frontend sent /api/plugins');
2841
2336
  const response = await this.getBaseRegisteredPlugins();
2842
- // this.log.debug('Response:', debugStringify(response));
2843
2337
  res.json(response);
2844
2338
  });
2845
- // Endpoint to provide devices
2846
2339
  this.expressApp.get('/api/devices', (req, res) => {
2847
2340
  this.log.debug('The frontend sent /api/devices');
2848
2341
  const devices = [];
@@ -2875,10 +2368,8 @@ export class Matterbridge extends EventEmitter {
2875
2368
  cluster: cluster,
2876
2369
  });
2877
2370
  });
2878
- // this.log.debug('Response:', debugStringify(data));
2879
2371
  res.json(devices);
2880
2372
  });
2881
- // Endpoint to provide the cluster servers of the devices
2882
2373
  this.expressApp.get('/api/devices_clusters/:selectedPluginName/:selectedDeviceEndpoint', (req, res) => {
2883
2374
  const selectedPluginName = req.params.selectedPluginName;
2884
2375
  const selectedDeviceEndpoint = parseInt(req.params.selectedDeviceEndpoint, 10);
@@ -2898,7 +2389,6 @@ export class Matterbridge extends EventEmitter {
2898
2389
  Object.entries(clusterServer.attributes).forEach(([key, value]) => {
2899
2390
  if (clusterServer.name === 'EveHistory')
2900
2391
  return;
2901
- // this.log.debug(`***--clusterServer: ${clusterServer.name}(${clusterServer.id}) attribute:${key}(${value.id}) ${value.isFixed} ${value.isWritable} ${value.isWritable}`);
2902
2392
  let attributeValue;
2903
2393
  try {
2904
2394
  if (typeof value.getLocal() === 'object')
@@ -2909,7 +2399,6 @@ export class Matterbridge extends EventEmitter {
2909
2399
  catch (error) {
2910
2400
  attributeValue = 'Fabric-Scoped';
2911
2401
  this.log.debug(`GetLocal value ${error} in clusterServer: ${clusterServer.name}(${clusterServer.id}) attribute: ${key}(${value.id})`);
2912
- // console.log(error);
2913
2402
  }
2914
2403
  data.push({
2915
2404
  endpoint: device.number ? device.number.toString() : '...',
@@ -2922,14 +2411,12 @@ export class Matterbridge extends EventEmitter {
2922
2411
  });
2923
2412
  });
2924
2413
  device.getChildEndpoints().forEach((childEndpoint) => {
2925
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
2926
2414
  const name = this.edge ? childEndpoint.endpoint?.id : childEndpoint.uniqueStorageKey;
2927
2415
  const clusterServers = childEndpoint.getAllClusterServers();
2928
2416
  clusterServers.forEach((clusterServer) => {
2929
2417
  Object.entries(clusterServer.attributes).forEach(([key, value]) => {
2930
2418
  if (clusterServer.name === 'EveHistory')
2931
2419
  return;
2932
- // this.log.debug(`***--clusterServer: ${clusterServer.name}(${clusterServer.id}) attribute:${key}(${value.id}) ${value.isFixed} ${value.isWritable} ${value.isWritable}`);
2933
2420
  let attributeValue;
2934
2421
  try {
2935
2422
  if (typeof value.getLocal() === 'object')
@@ -2940,7 +2427,6 @@ export class Matterbridge extends EventEmitter {
2940
2427
  catch (error) {
2941
2428
  attributeValue = 'Unavailable';
2942
2429
  this.log.debug(`GetLocal error ${error} in clusterServer: ${clusterServer.name}(${clusterServer.id}) attribute: ${key}(${value.id})`);
2943
- // console.log(error);
2944
2430
  }
2945
2431
  data.push({
2946
2432
  endpoint: (childEndpoint.number ? childEndpoint.number.toString() : '...') + (name ? ' (' + name + ')' : ''),
@@ -2957,7 +2443,6 @@ export class Matterbridge extends EventEmitter {
2957
2443
  });
2958
2444
  res.json(data);
2959
2445
  });
2960
- // Endpoint to view the log
2961
2446
  this.expressApp.get('/api/view-log', async (req, res) => {
2962
2447
  this.log.debug('The frontend sent /api/log');
2963
2448
  try {
@@ -2970,12 +2455,10 @@ export class Matterbridge extends EventEmitter {
2970
2455
  res.status(500).send('Error reading log file');
2971
2456
  }
2972
2457
  });
2973
- // Endpoint to download the matterbridge log
2974
2458
  this.expressApp.get('/api/download-mblog', async (req, res) => {
2975
2459
  this.log.debug('The frontend sent /api/download-mblog');
2976
2460
  try {
2977
2461
  await fs.access(path.join(this.matterbridgeDirectory, this.matterbrideLoggerFile), fs.constants.F_OK);
2978
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
2979
2462
  }
2980
2463
  catch (error) {
2981
2464
  fs.appendFile(path.join(this.matterbridgeDirectory, this.matterbrideLoggerFile), 'Enable the log on file in the settings to enable the file logger');
@@ -2987,12 +2470,10 @@ export class Matterbridge extends EventEmitter {
2987
2470
  }
2988
2471
  });
2989
2472
  });
2990
- // Endpoint to download the matter log
2991
2473
  this.expressApp.get('/api/download-mjlog', async (req, res) => {
2992
2474
  this.log.debug('The frontend sent /api/download-mjlog');
2993
2475
  try {
2994
2476
  await fs.access(path.join(this.matterbridgeDirectory, this.matterLoggerFile), fs.constants.F_OK);
2995
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
2996
2477
  }
2997
2478
  catch (error) {
2998
2479
  fs.appendFile(path.join(this.matterbridgeDirectory, this.matterLoggerFile), 'Enable the log on file in the settings to enable the file logger');
@@ -3004,7 +2485,6 @@ export class Matterbridge extends EventEmitter {
3004
2485
  }
3005
2486
  });
3006
2487
  });
3007
- // Endpoint to download the matter storage file
3008
2488
  this.expressApp.get('/api/download-mjstorage', (req, res) => {
3009
2489
  this.log.debug('The frontend sent /api/download-mjstorage');
3010
2490
  res.download(path.join(this.matterbridgeDirectory, this.matterStorageName), 'matterbridge.json', (error) => {
@@ -3014,7 +2494,6 @@ export class Matterbridge extends EventEmitter {
3014
2494
  }
3015
2495
  });
3016
2496
  });
3017
- // Endpoint to download the matterbridge storage directory
3018
2497
  this.expressApp.get('/api/download-mbstorage', async (req, res) => {
3019
2498
  this.log.debug('The frontend sent /api/download-mbstorage');
3020
2499
  await createZip(path.join(os.tmpdir(), `matterbridge.${this.nodeStorageName}.zip`), path.join(this.matterbridgeDirectory, this.nodeStorageName));
@@ -3025,7 +2504,6 @@ export class Matterbridge extends EventEmitter {
3025
2504
  }
3026
2505
  });
3027
2506
  });
3028
- // Endpoint to download the matterbridge plugin directory
3029
2507
  this.expressApp.get('/api/download-pluginstorage', async (req, res) => {
3030
2508
  this.log.debug('The frontend sent /api/download-pluginstorage');
3031
2509
  await createZip(path.join(os.tmpdir(), `matterbridge.pluginstorage.zip`), this.matterbridgePluginDirectory);
@@ -3036,11 +2514,9 @@ export class Matterbridge extends EventEmitter {
3036
2514
  }
3037
2515
  });
3038
2516
  });
3039
- // Endpoint to download the matterbridge plugin config files
3040
2517
  this.expressApp.get('/api/download-pluginconfig', async (req, res) => {
3041
2518
  this.log.debug('The frontend sent /api/download-pluginconfig');
3042
2519
  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
2520
  res.download(path.join(os.tmpdir(), `matterbridge.pluginconfig.zip`), `matterbridge.pluginconfig.zip`, (error) => {
3045
2521
  if (error) {
3046
2522
  this.log.error(`Error downloading file matterbridge.pluginstorage.zip: ${error instanceof Error ? error.message : error}`);
@@ -3048,7 +2524,6 @@ export class Matterbridge extends EventEmitter {
3048
2524
  }
3049
2525
  });
3050
2526
  });
3051
- // Endpoint to download the matterbridge plugin config files
3052
2527
  this.expressApp.get('/api/download-backup', async (req, res) => {
3053
2528
  this.log.debug('The frontend sent /api/download-backup');
3054
2529
  res.download(path.join(os.tmpdir(), `matterbridge.backup.zip`), `matterbridge.backup.zip`, (error) => {
@@ -3058,7 +2533,6 @@ export class Matterbridge extends EventEmitter {
3058
2533
  }
3059
2534
  });
3060
2535
  });
3061
- // Endpoint to receive commands
3062
2536
  this.expressApp.post('/api/command/:command/:param', express.json(), async (req, res) => {
3063
2537
  const command = req.params.command;
3064
2538
  let param = req.params.param;
@@ -3068,15 +2542,13 @@ export class Matterbridge extends EventEmitter {
3068
2542
  return;
3069
2543
  }
3070
2544
  this.log.debug(`Received frontend command: ${command}:${param}`);
3071
- // Handle the command setpassword from Settings
3072
2545
  if (command === 'setpassword') {
3073
- const password = param.slice(1, -1); // Remove the first and last characters
2546
+ const password = param.slice(1, -1);
3074
2547
  this.log.debug('setpassword', param, password);
3075
2548
  await this.nodeContext?.set('password', password);
3076
2549
  res.json({ message: 'Command received' });
3077
2550
  return;
3078
2551
  }
3079
- // Handle the command setbridgemode from Settings
3080
2552
  if (command === 'setbridgemode') {
3081
2553
  this.log.debug(`setbridgemode: ${param}`);
3082
2554
  this.wssSendRestartRequired();
@@ -3084,7 +2556,6 @@ export class Matterbridge extends EventEmitter {
3084
2556
  res.json({ message: 'Command received' });
3085
2557
  return;
3086
2558
  }
3087
- // Handle the command backup from Settings
3088
2559
  if (command === 'backup') {
3089
2560
  this.log.notice(`Prepairing the backup...`);
3090
2561
  await createZip(path.join(os.tmpdir(), `matterbridge.backup.zip`), path.join(this.matterbridgeDirectory), path.join(this.matterbridgePluginDirectory));
@@ -3092,26 +2563,25 @@ export class Matterbridge extends EventEmitter {
3092
2563
  res.json({ message: 'Command received' });
3093
2564
  return;
3094
2565
  }
3095
- // Handle the command setmbloglevel from Settings
3096
2566
  if (command === 'setmbloglevel') {
3097
2567
  this.log.debug('Matterbridge log level:', param);
3098
2568
  if (param === 'Debug') {
3099
- this.log.logLevel = "debug" /* LogLevel.DEBUG */;
2569
+ this.log.logLevel = "debug";
3100
2570
  }
3101
2571
  else if (param === 'Info') {
3102
- this.log.logLevel = "info" /* LogLevel.INFO */;
2572
+ this.log.logLevel = "info";
3103
2573
  }
3104
2574
  else if (param === 'Notice') {
3105
- this.log.logLevel = "notice" /* LogLevel.NOTICE */;
2575
+ this.log.logLevel = "notice";
3106
2576
  }
3107
2577
  else if (param === 'Warn') {
3108
- this.log.logLevel = "warn" /* LogLevel.WARN */;
2578
+ this.log.logLevel = "warn";
3109
2579
  }
3110
2580
  else if (param === 'Error') {
3111
- this.log.logLevel = "error" /* LogLevel.ERROR */;
2581
+ this.log.logLevel = "error";
3112
2582
  }
3113
2583
  else if (param === 'Fatal') {
3114
- this.log.logLevel = "fatal" /* LogLevel.FATAL */;
2584
+ this.log.logLevel = "fatal";
3115
2585
  }
3116
2586
  await this.nodeContext?.set('matterbridgeLogLevel', this.log.logLevel);
3117
2587
  MatterbridgeDevice.logLevel = this.log.logLevel;
@@ -3119,13 +2589,12 @@ export class Matterbridge extends EventEmitter {
3119
2589
  for (const plugin of this.plugins) {
3120
2590
  if (!plugin.platform || !plugin.platform.config)
3121
2591
  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);
2592
+ plugin.platform.log.logLevel = plugin.platform.config.debug ? "debug" : this.log.logLevel;
2593
+ await plugin.platform.onChangeLoggerLevel(plugin.platform.config.debug ? "debug" : this.log.logLevel);
3124
2594
  }
3125
2595
  res.json({ message: 'Command received' });
3126
2596
  return;
3127
2597
  }
3128
- // Handle the command setmbloglevel from Settings
3129
2598
  if (command === 'setmjloglevel') {
3130
2599
  this.log.debug('Matter.js log level:', param);
3131
2600
  if (param === 'Debug') {
@@ -3150,34 +2619,30 @@ export class Matterbridge extends EventEmitter {
3150
2619
  res.json({ message: 'Command received' });
3151
2620
  return;
3152
2621
  }
3153
- // Handle the command setmdnsinterface from Settings
3154
2622
  if (command === 'setmdnsinterface') {
3155
- param = param.slice(1, -1); // Remove the first and last characters *mdns*
2623
+ param = param.slice(1, -1);
3156
2624
  this.matterbridgeInformation.mattermdnsinterface = param;
3157
2625
  this.log.debug('Matter.js mdns interface:', param === '' ? 'All interfaces' : param);
3158
2626
  await this.nodeContext?.set('mattermdnsinterface', param);
3159
2627
  res.json({ message: 'Command received' });
3160
2628
  return;
3161
2629
  }
3162
- // Handle the command setipv4address from Settings
3163
2630
  if (command === 'setipv4address') {
3164
- param = param.slice(1, -1); // Remove the first and last characters *ip*
2631
+ param = param.slice(1, -1);
3165
2632
  this.matterbridgeInformation.matteripv4address = param;
3166
2633
  this.log.debug('Matter.js ipv4 address:', param === '' ? 'All ipv4 addresses' : param);
3167
2634
  await this.nodeContext?.set('matteripv4address', param);
3168
2635
  res.json({ message: 'Command received' });
3169
2636
  return;
3170
2637
  }
3171
- // Handle the command setipv6address from Settings
3172
2638
  if (command === 'setipv6address') {
3173
- param = param.slice(1, -1); // Remove the first and last characters *ip*
2639
+ param = param.slice(1, -1);
3174
2640
  this.matterbridgeInformation.matteripv6address = param;
3175
2641
  this.log.debug('Matter.js ipv6 address:', param === '' ? 'All ipv6 addresses' : param);
3176
2642
  await this.nodeContext?.set('matteripv6address', param);
3177
2643
  res.json({ message: 'Command received' });
3178
2644
  return;
3179
2645
  }
3180
- // Handle the command setmatterport from Settings
3181
2646
  if (command === 'setmatterport') {
3182
2647
  const port = Math.min(Math.max(parseInt(param), 5540), 5560);
3183
2648
  this.matterbridgeInformation.matterPort = port;
@@ -3186,7 +2651,6 @@ export class Matterbridge extends EventEmitter {
3186
2651
  res.json({ message: 'Command received' });
3187
2652
  return;
3188
2653
  }
3189
- // Handle the command setmatterdiscriminator from Settings
3190
2654
  if (command === 'setmatterdiscriminator') {
3191
2655
  const discriminator = Math.min(Math.max(parseInt(param), 1000), 4095);
3192
2656
  this.matterbridgeInformation.matterDiscriminator = discriminator;
@@ -3195,7 +2659,6 @@ export class Matterbridge extends EventEmitter {
3195
2659
  res.json({ message: 'Command received' });
3196
2660
  return;
3197
2661
  }
3198
- // Handle the command setmatterpasscode from Settings
3199
2662
  if (command === 'setmatterpasscode') {
3200
2663
  const passcode = Math.min(Math.max(parseInt(param), 10000000), 90000000);
3201
2664
  this.matterbridgeInformation.matterPasscode = passcode;
@@ -3204,20 +2667,17 @@ export class Matterbridge extends EventEmitter {
3204
2667
  res.json({ message: 'Command received' });
3205
2668
  return;
3206
2669
  }
3207
- // Handle the command setmbloglevel from Settings
3208
2670
  if (command === 'setmblogfile') {
3209
2671
  this.log.debug('Matterbridge file log:', param);
3210
2672
  this.matterbridgeInformation.fileLogger = param === 'true';
3211
2673
  await this.nodeContext?.set('matterbridgeFileLog', param === 'true');
3212
- // Create the file logger for matterbridge
3213
2674
  if (param === 'true')
3214
- AnsiLogger.setGlobalLogfile(path.join(this.matterbridgeDirectory, this.matterbrideLoggerFile), "debug" /* LogLevel.DEBUG */, true);
2675
+ AnsiLogger.setGlobalLogfile(path.join(this.matterbridgeDirectory, this.matterbrideLoggerFile), "debug", true);
3215
2676
  else
3216
2677
  AnsiLogger.setGlobalLogfile(undefined);
3217
2678
  res.json({ message: 'Command received' });
3218
2679
  return;
3219
2680
  }
3220
- // Handle the command setmbloglevel from Settings
3221
2681
  if (command === 'setmjlogfile') {
3222
2682
  this.log.debug('Matter file log:', param);
3223
2683
  this.matterbridgeInformation.matterFileLogger = param === 'true';
@@ -3244,43 +2704,36 @@ export class Matterbridge extends EventEmitter {
3244
2704
  res.json({ message: 'Command received' });
3245
2705
  return;
3246
2706
  }
3247
- // Handle the command unregister from Settings
3248
2707
  if (command === 'unregister') {
3249
2708
  await this.unregisterAndShutdownProcess();
3250
2709
  res.json({ message: 'Command received' });
3251
2710
  return;
3252
2711
  }
3253
- // Handle the command reset from Settings
3254
2712
  if (command === 'reset') {
3255
2713
  await this.shutdownProcessAndReset();
3256
2714
  res.json({ message: 'Command received' });
3257
2715
  return;
3258
2716
  }
3259
- // Handle the command factoryreset from Settings
3260
2717
  if (command === 'factoryreset') {
3261
2718
  await this.shutdownProcessAndFactoryReset();
3262
2719
  res.json({ message: 'Command received' });
3263
2720
  return;
3264
2721
  }
3265
- // Handle the command shutdown from Header
3266
2722
  if (command === 'shutdown') {
3267
2723
  await this.shutdownProcess();
3268
2724
  res.json({ message: 'Command received' });
3269
2725
  return;
3270
2726
  }
3271
- // Handle the command restart from Header
3272
2727
  if (command === 'restart') {
3273
2728
  await this.restartProcess();
3274
2729
  res.json({ message: 'Command received' });
3275
2730
  return;
3276
2731
  }
3277
- // Handle the command update from Header
3278
2732
  if (command === 'update') {
3279
2733
  this.log.info('Updating matterbridge...');
3280
2734
  try {
3281
2735
  await this.spawnCommand('npm', ['install', '-g', 'matterbridge', '--omit=dev', '--verbose']);
3282
2736
  this.log.info('Matterbridge has been updated. Full restart required.');
3283
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
3284
2737
  }
3285
2738
  catch (error) {
3286
2739
  this.log.error('Error updating matterbridge');
@@ -3290,11 +2743,9 @@ export class Matterbridge extends EventEmitter {
3290
2743
  res.json({ message: 'Command received' });
3291
2744
  return;
3292
2745
  }
3293
- // Handle the command saveconfig from Home
3294
2746
  if (command === 'saveconfig') {
3295
2747
  param = param.replace(/\*/g, '\\');
3296
2748
  this.log.info(`Saving config for plugin ${plg}${param}${nf}...`);
3297
- // console.log('Req.body:', JSON.stringify(req.body, null, 2));
3298
2749
  if (!this.plugins.has(param)) {
3299
2750
  this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
3300
2751
  }
@@ -3308,39 +2759,33 @@ export class Matterbridge extends EventEmitter {
3308
2759
  res.json({ message: 'Command received' });
3309
2760
  return;
3310
2761
  }
3311
- // Handle the command installplugin from Home
3312
2762
  if (command === 'installplugin') {
3313
2763
  param = param.replace(/\*/g, '\\');
3314
2764
  this.log.info(`Installing plugin ${plg}${param}${nf}...`);
3315
2765
  try {
3316
2766
  await this.spawnCommand('npm', ['install', '-g', param, '--omit=dev', '--verbose']);
3317
2767
  this.log.info(`Plugin ${plg}${param}${nf} installed. Full restart required.`);
3318
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
3319
2768
  }
3320
2769
  catch (error) {
3321
2770
  this.log.error(`Error installing plugin ${plg}${param}${er}`);
3322
2771
  }
3323
2772
  this.wssSendRestartRequired();
3324
2773
  param = param.split('@')[0];
3325
- // Also add the plugin to matterbridge so no return!
3326
2774
  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
2775
  res.json({ message: 'Command received' });
3329
2776
  return;
3330
2777
  }
3331
2778
  }
3332
- // Handle the command addplugin from Home
3333
2779
  if (command === 'addplugin' || command === 'installplugin') {
3334
2780
  param = param.replace(/\*/g, '\\');
3335
2781
  const plugin = await this.plugins.add(param);
3336
2782
  if (plugin) {
3337
- this.plugins.load(plugin, true, 'The plugin has been added', true); // No await do it in the background
2783
+ this.plugins.load(plugin, true, 'The plugin has been added', true);
3338
2784
  }
3339
2785
  res.json({ message: 'Command received' });
3340
2786
  this.wssSendRefreshRequired();
3341
2787
  return;
3342
2788
  }
3343
- // Handle the command removeplugin from Home
3344
2789
  if (command === 'removeplugin') {
3345
2790
  if (!this.plugins.has(param)) {
3346
2791
  this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
@@ -3354,7 +2799,6 @@ export class Matterbridge extends EventEmitter {
3354
2799
  this.wssSendRefreshRequired();
3355
2800
  return;
3356
2801
  }
3357
- // Handle the command enableplugin from Home
3358
2802
  if (command === 'enableplugin') {
3359
2803
  if (!this.plugins.has(param)) {
3360
2804
  this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
@@ -3372,14 +2816,13 @@ export class Matterbridge extends EventEmitter {
3372
2816
  plugin.registeredDevices = undefined;
3373
2817
  plugin.addedDevices = undefined;
3374
2818
  await this.plugins.enable(param);
3375
- this.plugins.load(plugin, true, 'The plugin has been enabled', true); // No await do it in the background
2819
+ this.plugins.load(plugin, true, 'The plugin has been enabled', true);
3376
2820
  }
3377
2821
  }
3378
2822
  res.json({ message: 'Command received' });
3379
2823
  this.wssSendRefreshRequired();
3380
2824
  return;
3381
2825
  }
3382
- // Handle the command disableplugin from Home
3383
2826
  if (command === 'disableplugin') {
3384
2827
  if (!this.plugins.has(param)) {
3385
2828
  this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
@@ -3396,7 +2839,6 @@ export class Matterbridge extends EventEmitter {
3396
2839
  return;
3397
2840
  }
3398
2841
  });
3399
- // Fallback for routing (must be the last route)
3400
2842
  this.expressApp.get('*', (req, res) => {
3401
2843
  this.log.debug('The frontend sent:', req.url);
3402
2844
  this.log.debug('Response send file:', path.join(this.rootDirectory, 'frontend/build/index.html'));
@@ -3404,11 +2846,6 @@ export class Matterbridge extends EventEmitter {
3404
2846
  });
3405
2847
  this.log.debug(`Frontend initialized on port ${YELLOW}${port}${db} static ${UNDERLINE}${path.join(this.rootDirectory, 'frontend/build')}${UNDERLINEOFF}${rs}`);
3406
2848
  }
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
2849
  getClusterTextFromDevice(device) {
3413
2850
  const stringifyUserLabel = (endpoint) => {
3414
2851
  const labelList = endpoint.getClusterServer(UserLabelCluster)?.attributes.labelList.getLocal();
@@ -3431,11 +2868,9 @@ export class Matterbridge extends EventEmitter {
3431
2868
  return '';
3432
2869
  };
3433
2870
  let attributes = '';
3434
- // this.log.debug(`***getClusterTextFromDevice: ${device.deviceName} (${device.name})`);
3435
2871
  const clusterServers = device.getAllClusterServers();
3436
2872
  clusterServers.forEach((clusterServer) => {
3437
2873
  try {
3438
- // this.log.debug(`**--clusterServer: ${clusterServer.id} (${clusterServer.name})`);
3439
2874
  if (clusterServer.name === 'OnOff')
3440
2875
  attributes += `OnOff: ${clusterServer.attributes.onOff.getLocal()} `;
3441
2876
  if (clusterServer.name === 'Switch')
@@ -3486,30 +2921,18 @@ export class Matterbridge extends EventEmitter {
3486
2921
  attributes += `${stringifyFixedLabel(device)} `;
3487
2922
  if (clusterServer.name === 'UserLabel')
3488
2923
  attributes += `${stringifyUserLabel(device)} `;
3489
- // this.log.debug(`*--clusterServer: ${clusterServer.id} (${clusterServer.name})`);
3490
2924
  }
3491
2925
  catch (error) {
3492
2926
  this.log.error(`getClusterTextFromDevice with ${clusterServer.name} error: ${error}`);
3493
2927
  }
3494
2928
  });
3495
- // this.log.debug(`*getClusterTextFromDevice: ${device.deviceName} (${device.name})`);
3496
2929
  return attributes;
3497
2930
  }
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
2931
  async startExtension(dataPath, extensionVersion, port = 5540) {
3505
- // Set the bridge mode
3506
2932
  this.bridgeMode = 'bridge';
3507
- // Set the first port to use
3508
2933
  this.port = port;
3509
- // Set Matterbridge logger
3510
- this.log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: "info" /* LogLevel.INFO */ });
2934
+ this.log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4, logLevel: "info" });
3511
2935
  this.log.debug('Matterbridge extension is starting...');
3512
- // Initialize NodeStorage
3513
2936
  this.matterbridgeDirectory = dataPath;
3514
2937
  this.log.debug('Creating node storage manager dir: ' + path.join(this.matterbridgeDirectory, 'node_storage'));
3515
2938
  this.nodeStorage = new NodeStorageManager({ dir: path.join(this.matterbridgeDirectory, 'node_storage'), logging: false });
@@ -3528,13 +2951,10 @@ export class Matterbridge extends EventEmitter {
3528
2951
  };
3529
2952
  this.plugins.set(plugin);
3530
2953
  this.plugins.saveToStorage();
3531
- // Log system info and create .matterbridge directory
3532
2954
  await this.logNodeAndSystemInfo();
3533
2955
  this.matterbridgeDirectory = dataPath;
3534
- // Set matter.js logger level and format
3535
2956
  Logger.defaultLogLevel = MatterLogLevel.INFO;
3536
2957
  Logger.format = MatterLogFormat.ANSI;
3537
- // Start the storage and create matterbridgeContext
3538
2958
  await this.startMatterStorage('json', path.join(this.matterbridgeDirectory, this.matterStorageName));
3539
2959
  if (!this.storageManager)
3540
2960
  return false;
@@ -3544,7 +2964,7 @@ export class Matterbridge extends EventEmitter {
3544
2964
  await this.matterbridgeContext.set('softwareVersion', 1);
3545
2965
  await this.matterbridgeContext.set('softwareVersionString', this.matterbridgeVersion);
3546
2966
  await this.matterbridgeContext.set('hardwareVersion', 1);
3547
- await this.matterbridgeContext.set('hardwareVersionString', extensionVersion); // Update with the extension version
2967
+ await this.matterbridgeContext.set('hardwareVersionString', extensionVersion);
3548
2968
  this.matterServer = this.createMatterServer(this.storageManager);
3549
2969
  this.log.debug(`Creating commissioning server for ${plg}Matterbridge${db}`);
3550
2970
  this.commissioningServer = await this.createCommisioningServer(this.matterbridgeContext, 'Matterbridge');
@@ -3557,7 +2977,6 @@ export class Matterbridge extends EventEmitter {
3557
2977
  await this.startMatterServer();
3558
2978
  this.log.info('Matter server started');
3559
2979
  await this.showCommissioningQRCode(this.commissioningServer, this.matterbridgeContext, this.nodeContext, 'Matterbridge');
3560
- // Set reachability to true and trigger event after 60 seconds
3561
2980
  setTimeout(() => {
3562
2981
  this.log.info(`Setting reachability to true for ${plg}Matterbridge${db}`);
3563
2982
  if (this.commissioningServer)
@@ -3567,31 +2986,14 @@ export class Matterbridge extends EventEmitter {
3567
2986
  }, 60 * 1000);
3568
2987
  return this.commissioningServer.isCommissioned();
3569
2988
  }
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
2989
  async stopExtension() {
3577
- // Closing matter
3578
2990
  await this.stopMatterServer();
3579
- // Clearing the session manager
3580
- // this.matterbridgeContext?.createContext('SessionManager').clear();
3581
- // Closing storage
3582
2991
  await this.stopMatterStorage();
3583
2992
  this.log.info('Matter server stopped');
3584
2993
  }
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
2994
  isExtensionCommissioned() {
3592
2995
  if (!this.commissioningServer)
3593
2996
  return false;
3594
2997
  return this.commissioningServer.isCommissioned();
3595
2998
  }
3596
2999
  }
3597
- //# sourceMappingURL=matterbridge.js.map