matterbridge 1.6.6 → 1.6.7-dev.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. package/CHANGELOG.md +22 -4
  2. package/README.md +5 -3
  3. package/dist/cli.js +0 -26
  4. package/dist/cluster/export.js +0 -2
  5. package/dist/defaultConfigSchema.js +0 -23
  6. package/dist/deviceManager.js +1 -26
  7. package/dist/index.js +0 -30
  8. package/dist/logger/export.js +0 -1
  9. package/dist/matter/export.js +1 -1
  10. package/dist/matterbridge.js +66 -706
  11. package/dist/matterbridgeAccessoryPlatform.js +0 -33
  12. package/dist/matterbridgeBehaviors.js +1 -29
  13. package/dist/matterbridgeDevice.js +11 -947
  14. package/dist/matterbridgeDeviceTypes.js +12 -59
  15. package/dist/matterbridgeDynamicPlatform.js +0 -33
  16. package/dist/matterbridgeEdge.js +147 -574
  17. package/dist/matterbridgeEndpoint.js +13 -1061
  18. package/dist/matterbridgePlatform.js +5 -94
  19. package/dist/matterbridgeTypes.js +0 -24
  20. package/dist/matterbridgeWebsocket.js +0 -45
  21. package/dist/pluginManager.js +11 -240
  22. package/dist/storage/export.js +0 -1
  23. package/dist/utils/colorUtils.js +2 -205
  24. package/dist/utils/export.js +0 -1
  25. package/dist/utils/utils.js +7 -252
  26. package/frontend/build/asset-manifest.json +3 -3
  27. package/frontend/build/index.html +1 -1
  28. package/frontend/build/static/js/{main.a742de4e.js → main.4dd7e165.js} +3 -3
  29. package/frontend/build/static/js/main.4dd7e165.js.map +1 -0
  30. package/npm-shrinkwrap.json +20 -16
  31. package/package.json +2 -3
  32. package/dist/cli.d.ts +0 -25
  33. package/dist/cli.d.ts.map +0 -1
  34. package/dist/cli.js.map +0 -1
  35. package/dist/cluster/export.d.ts +0 -2
  36. package/dist/cluster/export.d.ts.map +0 -1
  37. package/dist/cluster/export.js.map +0 -1
  38. package/dist/defaultConfigSchema.d.ts +0 -27
  39. package/dist/defaultConfigSchema.d.ts.map +0 -1
  40. package/dist/defaultConfigSchema.js.map +0 -1
  41. package/dist/deviceManager.d.ts +0 -46
  42. package/dist/deviceManager.d.ts.map +0 -1
  43. package/dist/deviceManager.js.map +0 -1
  44. package/dist/index.d.ts +0 -40
  45. package/dist/index.d.ts.map +0 -1
  46. package/dist/index.js.map +0 -1
  47. package/dist/logger/export.d.ts +0 -2
  48. package/dist/logger/export.d.ts.map +0 -1
  49. package/dist/logger/export.js.map +0 -1
  50. package/dist/matter/export.d.ts +0 -5
  51. package/dist/matter/export.d.ts.map +0 -1
  52. package/dist/matter/export.js.map +0 -1
  53. package/dist/matterbridge.d.ts +0 -466
  54. package/dist/matterbridge.d.ts.map +0 -1
  55. package/dist/matterbridge.js.map +0 -1
  56. package/dist/matterbridgeAccessoryPlatform.d.ts +0 -39
  57. package/dist/matterbridgeAccessoryPlatform.d.ts.map +0 -1
  58. package/dist/matterbridgeAccessoryPlatform.js.map +0 -1
  59. package/dist/matterbridgeBehaviors.d.ts +0 -942
  60. package/dist/matterbridgeBehaviors.d.ts.map +0 -1
  61. package/dist/matterbridgeBehaviors.js.map +0 -1
  62. package/dist/matterbridgeDevice.d.ts +0 -6674
  63. package/dist/matterbridgeDevice.d.ts.map +0 -1
  64. package/dist/matterbridgeDevice.js.map +0 -1
  65. package/dist/matterbridgeDeviceTypes.d.ts +0 -82
  66. package/dist/matterbridgeDeviceTypes.d.ts.map +0 -1
  67. package/dist/matterbridgeDeviceTypes.js.map +0 -1
  68. package/dist/matterbridgeDynamicPlatform.d.ts +0 -39
  69. package/dist/matterbridgeDynamicPlatform.d.ts.map +0 -1
  70. package/dist/matterbridgeDynamicPlatform.js.map +0 -1
  71. package/dist/matterbridgeEdge.d.ts +0 -89
  72. package/dist/matterbridgeEdge.d.ts.map +0 -1
  73. package/dist/matterbridgeEdge.js.map +0 -1
  74. package/dist/matterbridgeEndpoint.d.ts +0 -9774
  75. package/dist/matterbridgeEndpoint.d.ts.map +0 -1
  76. package/dist/matterbridgeEndpoint.js.map +0 -1
  77. package/dist/matterbridgePlatform.d.ts +0 -114
  78. package/dist/matterbridgePlatform.d.ts.map +0 -1
  79. package/dist/matterbridgePlatform.js.map +0 -1
  80. package/dist/matterbridgeTypes.d.ts +0 -161
  81. package/dist/matterbridgeTypes.d.ts.map +0 -1
  82. package/dist/matterbridgeTypes.js.map +0 -1
  83. package/dist/matterbridgeWebsocket.d.ts +0 -49
  84. package/dist/matterbridgeWebsocket.d.ts.map +0 -1
  85. package/dist/matterbridgeWebsocket.js.map +0 -1
  86. package/dist/pluginManager.d.ts +0 -238
  87. package/dist/pluginManager.d.ts.map +0 -1
  88. package/dist/pluginManager.js.map +0 -1
  89. package/dist/storage/export.d.ts +0 -2
  90. package/dist/storage/export.d.ts.map +0 -1
  91. package/dist/storage/export.js.map +0 -1
  92. package/dist/utils/colorUtils.d.ts +0 -61
  93. package/dist/utils/colorUtils.d.ts.map +0 -1
  94. package/dist/utils/colorUtils.js.map +0 -1
  95. package/dist/utils/export.d.ts +0 -3
  96. package/dist/utils/export.d.ts.map +0 -1
  97. package/dist/utils/export.js.map +0 -1
  98. package/dist/utils/utils.d.ts +0 -221
  99. package/dist/utils/utils.d.ts.map +0 -1
  100. package/dist/utils/utils.js.map +0 -1
  101. package/frontend/build/static/js/main.a742de4e.js.map +0 -1
  102. /package/frontend/build/static/js/{main.a742de4e.js.LICENSE.txt → main.4dd7e165.js.LICENSE.txt} +0 -0
@@ -1,26 +1,3 @@
1
- /**
2
- * This file contains the class Matterbridge.
3
- *
4
- * @file matterbridge.ts
5
- * @author Luca Liguori
6
- * @date 2023-12-29
7
- * @version 1.5.2
8
- *
9
- * Copyright 2023, 2024, 2025 Luca Liguori.
10
- *
11
- * Licensed under the Apache License, Version 2.0 (the "License");
12
- * you may not use this file except in compliance with the License.
13
- * You may obtain a copy of the License at
14
- *
15
- * http://www.apache.org/licenses/LICENSE-2.0
16
- *
17
- * Unless required by applicable law or agreed to in writing, software
18
- * distributed under the License is distributed on an "AS IS" BASIS,
19
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20
- * See the License for the specific language governing permissions and
21
- * limitations under the License. *
22
- */
23
- // Node.js modules
24
1
  import { fileURLToPath } from 'url';
25
2
  import { promises as fs } from 'fs';
26
3
  import { exec, spawn } from 'child_process';
@@ -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: '',
@@ -92,8 +60,9 @@ export class Matterbridge extends EventEmitter {
92
60
  bridgeMode: '',
93
61
  restartMode: '',
94
62
  edge: hasParameter('edge'),
63
+ readOnly: hasParameter('readonly'),
95
64
  profile: getParameter('profile'),
96
- loggerLevel: "info" /* LogLevel.INFO */,
65
+ loggerLevel: "info",
97
66
  fileLogger: false,
98
67
  matterLoggerLevel: MatterLogLevel.INFO,
99
68
  matterFileLogger: false,
@@ -132,7 +101,6 @@ export class Matterbridge extends EventEmitter {
132
101
  nodeContext;
133
102
  matterStorageName = 'matterbridge' + (getParameter('profile') ? '.' + getParameter('profile') : '') + '.json';
134
103
  nodeStorageName = 'storage' + (getParameter('profile') ? '.' + getParameter('profile') : '');
135
- // Cleanup
136
104
  hasCleanupStarted = false;
137
105
  initialized = false;
138
106
  execRunningCount = 0;
@@ -144,18 +112,16 @@ export class Matterbridge extends EventEmitter {
144
112
  sigtermHandler;
145
113
  exceptionHandler;
146
114
  rejectionHandler;
147
- // Frontend
148
115
  expressApp;
149
116
  httpServer;
150
117
  httpsServer;
151
118
  webSocketServer;
152
- // Matter
153
- mdnsInterface; // matter server mdnsInterface: e.g. 'eth0' or 'wlan0' or 'WiFi'
154
- ipv4address; // matter commissioning server listeningAddressIpv4
155
- ipv6address; // matter commissioning server listeningAddressIpv6
156
- port = 5540; // first commissioning server port
157
- passcode; // first commissioning server passcode
158
- discriminator; // first commissioning server discriminator
119
+ mdnsInterface;
120
+ ipv4address;
121
+ ipv6address;
122
+ port = 5540;
123
+ passcode;
124
+ discriminator;
159
125
  storageManager;
160
126
  matterbridgeContext;
161
127
  mattercontrollerContext;
@@ -166,26 +132,13 @@ export class Matterbridge extends EventEmitter {
166
132
  aggregatorVendorId = VendorId(getIntParameter('vendorId') ?? 0xfff1);
167
133
  aggregatorProductId = getIntParameter('productId') ?? 0x8000;
168
134
  static instance;
169
- // We load asyncronously so is private
170
135
  constructor() {
171
136
  super();
172
- // Bind the handler to the instance
173
137
  this.matterbridgeMessageHandler = wsMessageHandler.bind(this);
174
138
  }
175
139
  matterbridgeMessageHandler;
176
- /** ***********************************************************************************************************************************/
177
- /** loadInstance() and cleanup() methods */
178
- /** ***********************************************************************************************************************************/
179
- /**
180
- * Loads an instance of the Matterbridge class.
181
- * If an instance already exists, return that instance.
182
- *
183
- * @param initialize - Whether to initialize the Matterbridge instance after loading.
184
- * @returns The loaded Matterbridge instance.
185
- */
186
140
  static async loadInstance(initialize = false) {
187
141
  if (!Matterbridge.instance) {
188
- // eslint-disable-next-line no-console
189
142
  if (hasParameter('debug'))
190
143
  console.log(GREEN + 'Creating a new instance of Matterbridge.', initialize ? 'Initializing...' : 'Not initializing...', rs);
191
144
  Matterbridge.instance = new Matterbridge();
@@ -194,11 +147,6 @@ export class Matterbridge extends EventEmitter {
194
147
  }
195
148
  return Matterbridge.instance;
196
149
  }
197
- /**
198
- * Call cleanup().
199
- * @deprecated This method is deprecated and is only used for jest tests.
200
- *
201
- */
202
150
  async destroyInstance() {
203
151
  await this.cleanup('destroying instance...', false);
204
152
  await waiter('destroying instance...', () => {
@@ -206,60 +154,39 @@ export class Matterbridge extends EventEmitter {
206
154
  }, false, 60000, 100, false);
207
155
  await wait(1000, 'Wait for the global node_modules and matterbridge version', false);
208
156
  }
209
- /**
210
- * Initializes the Matterbridge application.
211
- *
212
- * @remarks
213
- * This method performs the necessary setup and initialization steps for the Matterbridge application.
214
- * It displays the help information if the 'help' parameter is provided, sets up the logger, checks the
215
- * node version, registers signal handlers, initializes storage, and parses the command line.
216
- *
217
- * @returns A Promise that resolves when the initialization is complete.
218
- */
219
157
  async initialize() {
220
- // Set the restart mode
221
158
  if (hasParameter('service'))
222
159
  this.restartMode = 'service';
223
160
  if (hasParameter('docker'))
224
161
  this.restartMode = 'docker';
225
- // Set the matterbridge directory
226
162
  this.homeDirectory = getParameter('homedir') ?? os.homedir();
227
163
  this.matterbridgeDirectory = path.join(this.homeDirectory, '.matterbridge');
228
- // Create matterbridge logger
229
- this.log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: hasParameter('debug') ? "debug" /* LogLevel.DEBUG */ : "info" /* LogLevel.INFO */ });
230
- // Initialize nodeStorage and nodeContext
164
+ this.log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4, logLevel: hasParameter('debug') ? "debug" : "info" });
231
165
  try {
232
166
  this.log.debug(`Creating node storage manager: ${CYAN}${this.nodeStorageName}${db}`);
233
167
  this.nodeStorage = new NodeStorageManager({ dir: path.join(this.matterbridgeDirectory, this.nodeStorageName), writeQueue: false, expiredInterval: undefined, logging: false });
234
168
  this.log.debug('Creating node storage context for matterbridge');
235
169
  this.nodeContext = await this.nodeStorage.createStorage('matterbridge');
236
- // TODO: Remove this code when node-persist-manager is updated
237
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
238
170
  const keys = (await this.nodeStorage?.storage.keys());
239
171
  for (const key of keys) {
240
172
  this.log.debug(`Checking node storage manager key: ${CYAN}${key}${db}`);
241
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
242
173
  await this.nodeStorage?.storage.get(key);
243
174
  }
244
175
  const storages = await this.nodeStorage.getStorageNames();
245
176
  for (const storage of storages) {
246
177
  this.log.debug(`Checking storage: ${CYAN}${storage}${db}`);
247
178
  const nodeContext = await this.nodeStorage?.createStorage(storage);
248
- // TODO: Remove this code when node-persist-manager is updated
249
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
250
179
  const keys = (await nodeContext?.storage.keys());
251
180
  keys.forEach(async (key) => {
252
181
  this.log.debug(`Checking key: ${CYAN}${storage}:${key}${db}`);
253
182
  await nodeContext?.get(key);
254
183
  });
255
184
  }
256
- // Creating a backup of the node storage since it is not corrupted
257
185
  this.log.debug('Creating node storage backup...');
258
186
  await copyDirectory(path.join(this.matterbridgeDirectory, this.nodeStorageName), path.join(this.matterbridgeDirectory, this.nodeStorageName + '.backup'));
259
187
  this.log.debug('Created node storage backup');
260
188
  }
261
189
  catch (error) {
262
- // Restoring the backup of the node storage since it is corrupted
263
190
  this.log.error(`Error creating node storage manager and context: ${error instanceof Error ? error.message : error}`);
264
191
  if (hasParameter('norestore')) {
265
192
  this.log.fatal(`The matterbridge node storage is corrupted. Parameter -norestore found: exiting...`);
@@ -274,50 +201,45 @@ export class Matterbridge extends EventEmitter {
274
201
  this.log.fatal('Fatal error creating node storage manager and context for matterbridge');
275
202
  throw new Error('Fatal error creating node storage manager and context for matterbridge');
276
203
  }
277
- // Set the first port to use for the commissioning server (will be incremented in childbridge mode)
278
204
  this.port = getIntParameter('port') ?? (await this.nodeContext.get('matterport', 5540)) ?? 5540;
279
- // Set the first passcode to use for the commissioning server (will be incremented in childbridge mode)
280
- this.passcode = getIntParameter('passcode') ?? (await this.nodeContext.get('matterpasscode'));
281
- // Set the first discriminator to use for the commissioning server (will be incremented in childbridge mode)
282
- this.discriminator = getIntParameter('discriminator') ?? (await this.nodeContext.get('matterdiscriminator'));
283
- // Set matterbridge logger level (context: matterbridgeLogLevel)
205
+ this.passcode = this.passcode ?? getIntParameter('passcode') ?? (await this.nodeContext.get('matterpasscode'));
206
+ this.discriminator = this.discriminator ?? getIntParameter('discriminator') ?? (await this.nodeContext.get('matterdiscriminator'));
207
+ this.log.debug(`Initializing commissioning server for Matterbridge... on port ${this.port} with passcode ${this.passcode} and discriminator ${this.discriminator}`);
284
208
  if (hasParameter('logger')) {
285
209
  const level = getParameter('logger');
286
210
  if (level === 'debug') {
287
- this.log.logLevel = "debug" /* LogLevel.DEBUG */;
211
+ this.log.logLevel = "debug";
288
212
  }
289
213
  else if (level === 'info') {
290
- this.log.logLevel = "info" /* LogLevel.INFO */;
214
+ this.log.logLevel = "info";
291
215
  }
292
216
  else if (level === 'notice') {
293
- this.log.logLevel = "notice" /* LogLevel.NOTICE */;
217
+ this.log.logLevel = "notice";
294
218
  }
295
219
  else if (level === 'warn') {
296
- this.log.logLevel = "warn" /* LogLevel.WARN */;
220
+ this.log.logLevel = "warn";
297
221
  }
298
222
  else if (level === 'error') {
299
- this.log.logLevel = "error" /* LogLevel.ERROR */;
223
+ this.log.logLevel = "error";
300
224
  }
301
225
  else if (level === 'fatal') {
302
- this.log.logLevel = "fatal" /* LogLevel.FATAL */;
226
+ this.log.logLevel = "fatal";
303
227
  }
304
228
  else {
305
229
  this.log.warn(`Invalid matterbridge logger level: ${level}. Using default level "info".`);
306
- this.log.logLevel = "info" /* LogLevel.INFO */;
230
+ this.log.logLevel = "info";
307
231
  }
308
232
  }
309
233
  else {
310
- this.log.logLevel = await this.nodeContext.get('matterbridgeLogLevel', "info" /* LogLevel.INFO */);
234
+ this.log.logLevel = await this.nodeContext.get('matterbridgeLogLevel', "info");
311
235
  }
312
236
  MatterbridgeDevice.logLevel = this.log.logLevel;
313
- // Create the file logger for matterbridge (context: matterbridgeFileLog)
314
237
  if (hasParameter('filelogger') || (await this.nodeContext.get('matterbridgeFileLog', false))) {
315
238
  AnsiLogger.setGlobalLogfile(path.join(this.matterbridgeDirectory, this.matterbrideLoggerFile), this.log.logLevel, true);
316
239
  this.matterbridgeInformation.fileLogger = true;
317
240
  }
318
241
  this.log.notice('Matterbridge is starting...');
319
242
  this.log.debug(`Matterbridge logLevel: ${this.log.logLevel} fileLoger: ${this.matterbridgeInformation.fileLogger}.`);
320
- // Set matter.js logger level, format and logger (context: matterLogLevel)
321
243
  if (hasParameter('matterlogger')) {
322
244
  const level = getParameter('matterlogger');
323
245
  if (level === 'debug') {
@@ -348,7 +270,6 @@ export class Matterbridge extends EventEmitter {
348
270
  }
349
271
  Logger.format = MatterLogFormat.ANSI;
350
272
  Logger.setLogger('default', this.createMatterLogger());
351
- // Create the file logger for matter.js (context: matterFileLog)
352
273
  if (hasParameter('matterfilelogger') || (await this.nodeContext.get('matterFileLog', false))) {
353
274
  this.matterbridgeInformation.matterFileLogger = true;
354
275
  Logger.addLogger('matterfilelogger', await this.createMatterFileLogger(path.join(this.matterbridgeDirectory, this.matterLoggerFile), true), {
@@ -357,7 +278,6 @@ export class Matterbridge extends EventEmitter {
357
278
  });
358
279
  }
359
280
  this.log.debug(`Matter logLevel: ${Logger.defaultLogLevel} fileLoger: ${this.matterbridgeInformation.matterFileLogger}.`);
360
- // Set the interface to use for the matter server mdnsInterface
361
281
  if (hasParameter('mdnsinterface')) {
362
282
  this.mdnsInterface = getParameter('mdnsinterface');
363
283
  }
@@ -366,7 +286,6 @@ export class Matterbridge extends EventEmitter {
366
286
  if (this.mdnsInterface === '')
367
287
  this.mdnsInterface = undefined;
368
288
  }
369
- // Set the listeningAddressIpv4 for the matter commissioning server
370
289
  if (hasParameter('ipv4address')) {
371
290
  this.ipv4address = getParameter('ipv4address');
372
291
  }
@@ -375,7 +294,6 @@ export class Matterbridge extends EventEmitter {
375
294
  if (this.ipv4address === '')
376
295
  this.ipv4address = undefined;
377
296
  }
378
- // Set the listeningAddressIpv6 for the matter commissioning server
379
297
  if (hasParameter('ipv6address')) {
380
298
  this.ipv6address = getParameter('ipv6address');
381
299
  }
@@ -384,23 +302,17 @@ export class Matterbridge extends EventEmitter {
384
302
  if (this.ipv6address === '')
385
303
  this.ipv6address = undefined;
386
304
  }
387
- // Initialize PluginManager
388
305
  this.plugins = new PluginManager(this);
389
306
  await this.plugins.loadFromStorage();
390
- // Initialize DeviceManager
391
307
  this.devices = new DeviceManager(this, this.nodeContext);
392
- // Get the plugins from node storage and create the plugins node storage contexts
393
308
  for (const plugin of this.plugins) {
394
309
  const packageJson = await this.plugins.parse(plugin);
395
310
  if (packageJson === null && !hasParameter('add')) {
396
- // Try to reinstall the plugin from npm (for Docker pull and external plugins)
397
- // We don't do this when the add parameter is set because we shut down the process after adding the plugin
398
311
  this.log.info(`Error parsing plugin ${plg}${plugin.name}${nf}. Trying to reinstall it from npm.`);
399
312
  try {
400
313
  await this.spawnCommand('npm', ['install', '-g', plugin.name, '--omit=dev', '--verbose']);
401
314
  this.log.info(`Plugin ${plg}${plugin.name}${nf} reinstalled.`);
402
315
  plugin.error = false;
403
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
404
316
  }
405
317
  catch (error) {
406
318
  plugin.error = true;
@@ -417,7 +329,6 @@ export class Matterbridge extends EventEmitter {
417
329
  await plugin.nodeContext.set('description', plugin.description);
418
330
  await plugin.nodeContext.set('author', plugin.author);
419
331
  }
420
- // Log system info and create .matterbridge directory
421
332
  await this.logNodeAndSystemInfo();
422
333
  this.log.notice(`Matterbridge version ${this.matterbridgeVersion} ` +
423
334
  `${hasParameter('bridge') || (!hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'bridge') ? 'mode bridge ' : ''}` +
@@ -425,7 +336,6 @@ export class Matterbridge extends EventEmitter {
425
336
  `${hasParameter('controller') ? 'mode controller ' : ''}` +
426
337
  `${this.restartMode !== '' ? 'restart mode ' + this.restartMode + ' ' : ''}` +
427
338
  `running on ${this.systemInformation.osType} (v.${this.systemInformation.osRelease}) platform ${this.systemInformation.osPlatform} arch ${this.systemInformation.osArch}`);
428
- // Check node version and throw error
429
339
  const minNodeVersion = 18;
430
340
  const nodeVersion = process.versions.node;
431
341
  const versionMajor = parseInt(nodeVersion.split('.')[0]);
@@ -433,17 +343,10 @@ export class Matterbridge extends EventEmitter {
433
343
  this.log.error(`Node version ${versionMajor} is not supported. Please upgrade to ${minNodeVersion} or above.`);
434
344
  throw new Error(`Node version ${versionMajor} is not supported. Please upgrade to ${minNodeVersion} or above.`);
435
345
  }
436
- // Register process handlers
437
346
  this.registerProcessHandlers();
438
- // Parse command line
439
347
  await this.parseCommandLine();
440
348
  this.initialized = true;
441
349
  }
442
- /**
443
- * Parses the command line arguments and performs the corresponding actions.
444
- * @private
445
- * @returns {Promise<void>} A promise that resolves when the command line arguments have been processed, or the process exits.
446
- */
447
350
  async parseCommandLine() {
448
351
  if (hasParameter('help')) {
449
352
  this.log.info(`\nUsage: matterbridge [options]\n
@@ -551,14 +454,12 @@ export class Matterbridge extends EventEmitter {
551
454
  }
552
455
  if (hasParameter('factoryreset')) {
553
456
  try {
554
- // Delete matter storage file
555
457
  await fs.unlink(path.join(this.matterbridgeDirectory, this.matterStorageName));
556
458
  }
557
459
  catch (err) {
558
460
  this.log.error(`Error deleting storage: ${err}`);
559
461
  }
560
462
  try {
561
- // Delete node storage directory with its subdirectories
562
463
  await fs.rm(path.join(this.matterbridgeDirectory, this.nodeStorageName), { recursive: true });
563
464
  }
564
465
  catch (err) {
@@ -572,7 +473,6 @@ export class Matterbridge extends EventEmitter {
572
473
  this.emit('shutdown');
573
474
  return;
574
475
  }
575
- // Start the matter storage and create the matterbridge context
576
476
  try {
577
477
  await this.startMatterStorage('json', path.join(this.matterbridgeDirectory, this.matterStorageName));
578
478
  }
@@ -607,34 +507,28 @@ export class Matterbridge extends EventEmitter {
607
507
  this.emit('shutdown');
608
508
  return;
609
509
  }
610
- // Initialize frontend
611
510
  if (getIntParameter('frontend') !== 0 || getIntParameter('frontend') === undefined)
612
511
  await this.initializeFrontend(getIntParameter('frontend'));
613
- // Check each 60 minutes the latest versions
614
512
  this.checkUpdateInterval = setInterval(() => {
615
513
  this.getMatterbridgeLatestVersion();
616
514
  for (const plugin of this.plugins) {
617
515
  this.getPluginLatestVersion(plugin);
618
516
  }
619
517
  }, 60 * 60 * 1000);
620
- // Start the matterbridge in mode test
621
518
  if (hasParameter('test')) {
622
519
  this.bridgeMode = 'bridge';
623
520
  MatterbridgeDevice.bridgeMode = 'bridge';
624
521
  return;
625
522
  }
626
- // Start the matterbridge in mode controller
627
523
  if (hasParameter('controller')) {
628
524
  this.bridgeMode = 'controller';
629
525
  await this.startController();
630
526
  return;
631
527
  }
632
- // Check if the bridge mode is set and start matterbridge in bridge mode if not set
633
528
  if (!hasParameter('bridge') && !hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === '') {
634
529
  this.log.info('Setting default matterbridge start mode to bridge');
635
530
  await this.nodeContext?.set('bridgeMode', 'bridge');
636
531
  }
637
- // Start matterbridge in bridge mode
638
532
  if (hasParameter('bridge') || (!hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'bridge')) {
639
533
  this.bridgeMode = 'bridge';
640
534
  MatterbridgeDevice.bridgeMode = 'bridge';
@@ -643,7 +537,6 @@ export class Matterbridge extends EventEmitter {
643
537
  await this.startBridge();
644
538
  return;
645
539
  }
646
- // Start matterbridge in childbridge mode
647
540
  if (hasParameter('childbridge') || (!hasParameter('bridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'childbridge')) {
648
541
  this.bridgeMode = 'childbridge';
649
542
  MatterbridgeDevice.bridgeMode = 'childbridge';
@@ -653,28 +546,17 @@ export class Matterbridge extends EventEmitter {
653
546
  return;
654
547
  }
655
548
  }
656
- /**
657
- * Asynchronously loads and starts the registered plugins.
658
- *
659
- * This method is responsible for initializing and staarting all enabled plugins.
660
- * It ensures that each plugin is properly loaded and started before the ridge starts.
661
- *
662
- * @returns {Promise<void>} A promise that resolves when all plugins have been loaded and started.
663
- */
664
549
  async startPlugins() {
665
- // Check, load and start the plugins
666
550
  for (const plugin of this.plugins) {
667
551
  plugin.configJson = await this.plugins.loadConfig(plugin);
668
552
  plugin.schemaJson = await this.plugins.loadSchema(plugin);
669
- // Check if the plugin is available
670
553
  if (!(await this.plugins.resolve(plugin.path))) {
671
554
  this.log.error(`Plugin ${plg}${plugin.name}${er} not found or not validated. Disabling it.`);
672
555
  plugin.enabled = false;
673
556
  plugin.error = true;
674
557
  continue;
675
558
  }
676
- // Check if the plugin has a new version
677
- this.getPluginLatestVersion(plugin); // No await do it asyncronously
559
+ this.getPluginLatestVersion(plugin);
678
560
  if (!plugin.enabled) {
679
561
  this.log.info(`Plugin ${plg}${plugin.name}${nf} not enabled`);
680
562
  continue;
@@ -689,26 +571,20 @@ export class Matterbridge extends EventEmitter {
689
571
  plugin.addedDevices = undefined;
690
572
  plugin.qrPairingCode = undefined;
691
573
  plugin.manualPairingCode = undefined;
692
- this.plugins.load(plugin, true, 'Matterbridge is starting'); // No await do it asyncronously
574
+ this.plugins.load(plugin, true, 'Matterbridge is starting');
693
575
  }
694
576
  this.wssSendRefreshRequired();
695
577
  }
696
- /**
697
- * Registers the process handlers for uncaughtException, unhandledRejection, SIGINT and SIGTERM.
698
- * When either of these signals are received, the cleanup method is called with an appropriate message.
699
- */
700
578
  registerProcessHandlers() {
701
579
  this.log.debug(`Registering uncaughtException and unhandledRejection handlers...`);
702
580
  process.removeAllListeners('uncaughtException');
703
581
  process.removeAllListeners('unhandledRejection');
704
582
  this.exceptionHandler = async (error) => {
705
583
  this.log.fatal('Unhandled Exception detected at:', error.stack || error, rs);
706
- // await this.cleanup('Unhandled Exception detected, cleaning up...');
707
584
  };
708
585
  process.on('uncaughtException', this.exceptionHandler);
709
586
  this.rejectionHandler = async (reason, promise) => {
710
587
  this.log.fatal('Unhandled Rejection detected at:', promise, 'reason:', reason instanceof Error ? reason.stack : reason, rs);
711
- // await this.cleanup('Unhandled Rejection detected, cleaning up...');
712
588
  };
713
589
  process.on('unhandledRejection', this.rejectionHandler);
714
590
  this.log.debug(`Registering SIGINT and SIGTERM signal handlers...`);
@@ -721,9 +597,6 @@ export class Matterbridge extends EventEmitter {
721
597
  };
722
598
  process.on('SIGTERM', this.sigtermHandler);
723
599
  }
724
- /**
725
- * Deregisters the process uncaughtException, unhandledRejection, SIGINT and SIGTERM signal handlers.
726
- */
727
600
  deregisterProcesslHandlers() {
728
601
  this.log.debug(`Deregistering uncaughtException and unhandledRejection handlers...`);
729
602
  if (this.exceptionHandler)
@@ -740,11 +613,7 @@ export class Matterbridge extends EventEmitter {
740
613
  process.off('SIGTERM', this.sigtermHandler);
741
614
  this.sigtermHandler = undefined;
742
615
  }
743
- /**
744
- * Logs the node and system information.
745
- */
746
616
  async logNodeAndSystemInfo() {
747
- // IP address information
748
617
  const networkInterfaces = os.networkInterfaces();
749
618
  this.systemInformation.ipv4Address = '';
750
619
  this.systemInformation.ipv6Address = '';
@@ -764,7 +633,7 @@ export class Matterbridge extends EventEmitter {
764
633
  this.systemInformation.macAddress = detail.mac;
765
634
  }
766
635
  }
767
- if (this.systemInformation.ipv4Address !== '' /* && this.systemInformation.ipv6Address !== ''*/) {
636
+ if (this.systemInformation.ipv4Address !== '') {
768
637
  this.log.debug(`Using interface: '${this.systemInformation.interfaceName}'`);
769
638
  this.log.debug(`- with MAC address: '${this.systemInformation.macAddress}'`);
770
639
  this.log.debug(`- with IPv4 address: '${this.systemInformation.ipv4Address}'`);
@@ -772,22 +641,19 @@ export class Matterbridge extends EventEmitter {
772
641
  break;
773
642
  }
774
643
  }
775
- // Node information
776
644
  this.systemInformation.nodeVersion = process.versions.node;
777
645
  const versionMajor = parseInt(this.systemInformation.nodeVersion.split('.')[0]);
778
646
  const versionMinor = parseInt(this.systemInformation.nodeVersion.split('.')[1]);
779
647
  const versionPatch = parseInt(this.systemInformation.nodeVersion.split('.')[2]);
780
- // Host system information
781
648
  this.systemInformation.hostname = os.hostname();
782
649
  this.systemInformation.user = os.userInfo().username;
783
- this.systemInformation.osType = os.type(); // "Windows_NT", "Darwin", etc.
784
- this.systemInformation.osRelease = os.release(); // Kernel version
785
- this.systemInformation.osPlatform = os.platform(); // "win32", "linux", "darwin", etc.
786
- this.systemInformation.osArch = os.arch(); // "x64", "arm", etc.
787
- this.systemInformation.totalMemory = (os.totalmem() / 1024 / 1024 / 1024).toFixed(2) + ' GB'; // Convert to GB
788
- this.systemInformation.freeMemory = (os.freemem() / 1024 / 1024 / 1024).toFixed(2) + ' GB'; // Convert to GB
789
- this.systemInformation.systemUptime = (os.uptime() / 60 / 60).toFixed(2) + ' hours'; // Convert to hours
790
- // 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';
791
657
  this.log.debug('Host System Information:');
792
658
  this.log.debug(`- Hostname: ${this.systemInformation.hostname}`);
793
659
  this.log.debug(`- User: ${this.systemInformation.user}`);
@@ -803,19 +669,15 @@ export class Matterbridge extends EventEmitter {
803
669
  this.log.debug(`- Total Memory: ${this.systemInformation.totalMemory}`);
804
670
  this.log.debug(`- Free Memory: ${this.systemInformation.freeMemory}`);
805
671
  this.log.debug(`- System Uptime: ${this.systemInformation.systemUptime}`);
806
- // Home directory
807
672
  this.homeDirectory = getParameter('homedir') ?? os.homedir();
808
673
  this.matterbridgeInformation.homeDirectory = this.homeDirectory;
809
674
  this.log.debug(`Home Directory: ${this.homeDirectory}`);
810
- // Package root directory
811
675
  const currentFileDirectory = path.dirname(fileURLToPath(import.meta.url));
812
676
  this.rootDirectory = path.resolve(currentFileDirectory, '../');
813
677
  this.matterbridgeInformation.rootDirectory = this.rootDirectory;
814
678
  this.log.debug(`Root Directory: ${this.rootDirectory}`);
815
- // Global node_modules directory
816
679
  if (this.nodeContext)
817
680
  this.globalModulesDirectory = await this.nodeContext.get('globalModulesDirectory', '');
818
- // First run of Matterbridge so the node storage is empty
819
681
  if (this.globalModulesDirectory === '') {
820
682
  try {
821
683
  this.globalModulesDirectory = await this.getGlobalNodeModules();
@@ -839,7 +701,6 @@ export class Matterbridge extends EventEmitter {
839
701
  this.log.error(`Error getting global node_modules directory: ${error}`);
840
702
  });
841
703
  }
842
- // Create the data directory .matterbridge in the home directory
843
704
  this.matterbridgeDirectory = path.join(this.homeDirectory, '.matterbridge');
844
705
  this.matterbridgeInformation.matterbridgeDirectory = this.matterbridgeDirectory;
845
706
  try {
@@ -863,7 +724,6 @@ export class Matterbridge extends EventEmitter {
863
724
  }
864
725
  }
865
726
  this.log.debug(`Matterbridge Directory: ${this.matterbridgeDirectory}`);
866
- // Create the plugin directory Matterbridge in the home directory
867
727
  this.matterbridgePluginDirectory = path.join(this.homeDirectory, 'Matterbridge');
868
728
  this.matterbridgeInformation.matterbridgePluginDirectory = this.matterbridgePluginDirectory;
869
729
  try {
@@ -887,28 +747,19 @@ export class Matterbridge extends EventEmitter {
887
747
  }
888
748
  }
889
749
  this.log.debug(`Matterbridge Plugin Directory: ${this.matterbridgePluginDirectory}`);
890
- // Matterbridge version
891
750
  const packageJson = JSON.parse(await fs.readFile(path.join(this.rootDirectory, 'package.json'), 'utf-8'));
892
751
  this.matterbridgeVersion = packageJson.version;
893
752
  this.matterbridgeInformation.matterbridgeVersion = this.matterbridgeVersion;
894
753
  this.log.debug(`Matterbridge Version: ${this.matterbridgeVersion}`);
895
- // Matterbridge latest version
896
754
  if (this.nodeContext)
897
755
  this.matterbridgeLatestVersion = await this.nodeContext.get('matterbridgeLatestVersion', '');
898
756
  this.log.debug(`Matterbridge Latest Version: ${this.matterbridgeLatestVersion}`);
899
757
  this.getMatterbridgeLatestVersion();
900
- // Current working directory
901
758
  const currentDir = process.cwd();
902
759
  this.log.debug(`Current Working Directory: ${currentDir}`);
903
- // Command line arguments (excluding 'node' and the script name)
904
760
  const cmdArgs = process.argv.slice(2).join(' ');
905
761
  this.log.debug(`Command Line Arguments: ${cmdArgs}`);
906
762
  }
907
- /**
908
- * Retrieves the latest version of a package from the npm registry.
909
- * @param packageName - The name of the package.
910
- * @returns A Promise that resolves to the latest version of the package.
911
- */
912
763
  async getLatestVersion(packageName) {
913
764
  return new Promise((resolve, reject) => {
914
765
  this.execRunningCount++;
@@ -923,10 +774,6 @@ export class Matterbridge extends EventEmitter {
923
774
  });
924
775
  });
925
776
  }
926
- /**
927
- * Retrieves the path to the global Node.js modules directory.
928
- * @returns A promise that resolves to the path of the global Node.js modules directory.
929
- */
930
777
  async getGlobalNodeModules() {
931
778
  return new Promise((resolve, reject) => {
932
779
  this.execRunningCount++;
@@ -941,11 +788,6 @@ export class Matterbridge extends EventEmitter {
941
788
  });
942
789
  });
943
790
  }
944
- /**
945
- * Retrieves the latest version of Matterbridge and performs necessary actions based on the version comparison.
946
- * @private
947
- * @returns {Promise<void>} A promise that resolves when the latest version is retrieved and actions are performed.
948
- */
949
791
  async getMatterbridgeLatestVersion() {
950
792
  this.getLatestVersion('matterbridge')
951
793
  .then(async (matterbridgeLatestVersion) => {
@@ -962,19 +804,8 @@ export class Matterbridge extends EventEmitter {
962
804
  })
963
805
  .catch((error) => {
964
806
  this.log.error(`Error getting Matterbridge latest version: ${error.message}`);
965
- // error.stack && this.log.debug(error.stack);
966
807
  });
967
808
  }
968
- /**
969
- * Retrieves the latest version of a plugin and updates the plugin's latestVersion property.
970
- * If the plugin's version is different from the latest version, logs a warning message.
971
- * If the plugin's version is the same as the latest version, logs an info message.
972
- * If there is an error retrieving the latest version, logs an error message.
973
- *
974
- * @private
975
- * @param {RegisteredPlugin} plugin - The plugin for which to retrieve the latest version.
976
- * @returns {Promise<void>} A promise that resolves when the latest version is retrieved and actions are performed.
977
- */
978
809
  async getPluginLatestVersion(plugin) {
979
810
  this.getLatestVersion(plugin.name)
980
811
  .then(async (latestVersion) => {
@@ -986,54 +817,40 @@ export class Matterbridge extends EventEmitter {
986
817
  })
987
818
  .catch((error) => {
988
819
  this.log.error(`Error getting ${plg}${plugin.name}${er} latest version: ${error.message}`);
989
- // error.stack && this.log.debug(error.stack);
990
820
  });
991
821
  }
992
- /**
993
- * Creates a MatterLogger function to show the matter.js log messages in AnsiLogger (for the frontend).
994
- *
995
- * @returns {Function} The MatterLogger function.
996
- */
997
822
  createMatterLogger() {
998
- 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" });
999
824
  return (_level, formattedLog) => {
1000
825
  const logger = formattedLog.slice(44, 44 + 20).trim();
1001
826
  const message = formattedLog.slice(65);
1002
827
  matterLogger.logName = logger;
1003
828
  switch (_level) {
1004
829
  case MatterLogLevel.DEBUG:
1005
- matterLogger.log("debug" /* LogLevel.DEBUG */, message);
830
+ matterLogger.log("debug", message);
1006
831
  break;
1007
832
  case MatterLogLevel.INFO:
1008
- matterLogger.log("info" /* LogLevel.INFO */, message);
833
+ matterLogger.log("info", message);
1009
834
  break;
1010
835
  case MatterLogLevel.NOTICE:
1011
- matterLogger.log("notice" /* LogLevel.NOTICE */, message);
836
+ matterLogger.log("notice", message);
1012
837
  break;
1013
838
  case MatterLogLevel.WARN:
1014
- matterLogger.log("warn" /* LogLevel.WARN */, message);
839
+ matterLogger.log("warn", message);
1015
840
  break;
1016
841
  case MatterLogLevel.ERROR:
1017
- matterLogger.log("error" /* LogLevel.ERROR */, message);
842
+ matterLogger.log("error", message);
1018
843
  break;
1019
844
  case MatterLogLevel.FATAL:
1020
- matterLogger.log("fatal" /* LogLevel.FATAL */, message);
845
+ matterLogger.log("fatal", message);
1021
846
  break;
1022
847
  default:
1023
- matterLogger.log("debug" /* LogLevel.DEBUG */, message);
848
+ matterLogger.log("debug", message);
1024
849
  break;
1025
850
  }
1026
851
  };
1027
852
  }
1028
- /**
1029
- * Creates a Matter File Logger.
1030
- *
1031
- * @param {string} filePath - The path to the log file.
1032
- * @param {boolean} [unlink=false] - Whether to unlink the log file before creating a new one.
1033
- * @returns {Function} - A function that logs formatted messages to the log file.
1034
- */
1035
853
  async createMatterFileLogger(filePath, unlink = false) {
1036
- // 2024-08-21 08:55:19.488 DEBUG InteractionMessenger Sending DataReport chunk with 28 attributes and 0 events: 1004 bytes
1037
854
  let fileSize = 0;
1038
855
  if (unlink) {
1039
856
  try {
@@ -1082,83 +899,53 @@ export class Matterbridge extends EventEmitter {
1082
899
  }
1083
900
  };
1084
901
  }
1085
- /**
1086
- * Update matterbridge and cleanup.
1087
- */
1088
902
  async updateProcess() {
1089
903
  await this.cleanup('updating...', false);
1090
904
  }
1091
- /**
1092
- * Restarts the process by spawning a new process and exiting the current process.
1093
- */
1094
905
  async restartProcess() {
1095
906
  await this.cleanup('restarting...', true);
1096
907
  }
1097
- /**
1098
- * Shut down the process by exiting the current process.
1099
- */
1100
908
  async shutdownProcess() {
1101
909
  await this.cleanup('shutting down...', false);
1102
910
  }
1103
- /**
1104
- * Shut down the process and reset.
1105
- */
1106
911
  async unregisterAndShutdownProcess() {
1107
912
  this.log.info('Unregistering all devices and shutting down...');
1108
- for (const plugin of this.plugins /* .filter((plugin) => plugin.enabled && !plugin.error))*/) {
913
+ for (const plugin of this.plugins) {
1109
914
  await this.removeAllBridgedDevices(plugin.name);
1110
915
  }
1111
916
  await this.cleanup('unregistered all devices and shutting down...', false);
1112
917
  }
1113
- /**
1114
- * Shut down the process and reset.
1115
- */
1116
918
  async shutdownProcessAndReset() {
1117
919
  await this.cleanup('shutting down with reset...', false);
1118
920
  }
1119
- /**
1120
- * Shut down the process and factory reset.
1121
- */
1122
921
  async shutdownProcessAndFactoryReset() {
1123
922
  await this.cleanup('shutting down with factory reset...', false);
1124
923
  }
1125
- /**
1126
- * Cleans up the Matterbridge instance.
1127
- * @param message - The cleanup message.
1128
- * @param restart - Indicates whether to restart the instance after cleanup. Default is `false`.
1129
- * @returns A promise that resolves when the cleanup is completed.
1130
- */
1131
924
  async cleanup(message, restart = false) {
1132
925
  if (this.initialized && !this.hasCleanupStarted) {
1133
926
  this.hasCleanupStarted = true;
1134
927
  this.log.info(message);
1135
- // Deregisters the process handlers
1136
928
  this.deregisterProcesslHandlers();
1137
- // Clear the start matter interval
1138
929
  if (this.startMatterInterval) {
1139
930
  clearInterval(this.startMatterInterval);
1140
931
  this.startMatterInterval = undefined;
1141
932
  this.log.debug('Start matter interval cleared');
1142
933
  }
1143
- // Clear the check update interval
1144
934
  if (this.checkUpdateInterval) {
1145
935
  clearInterval(this.checkUpdateInterval);
1146
936
  this.checkUpdateInterval = undefined;
1147
937
  this.log.debug('Check update interval cleared');
1148
938
  }
1149
- // Clear the configure timeout
1150
939
  if (this.configureTimeout) {
1151
940
  clearTimeout(this.configureTimeout);
1152
941
  this.configureTimeout = undefined;
1153
942
  this.log.debug('Matterbridge configure timeout cleared');
1154
943
  }
1155
- // Clear the reachability timeout
1156
944
  if (this.reachabilityTimeout) {
1157
945
  clearTimeout(this.reachabilityTimeout);
1158
946
  this.reachabilityTimeout = undefined;
1159
947
  this.log.debug('Matterbridge reachability timeout cleared');
1160
948
  }
1161
- // Calling the shutdown method of each plugin and clear the reachability timeout
1162
949
  for (const plugin of this.plugins) {
1163
950
  if (!plugin.enabled || plugin.error)
1164
951
  continue;
@@ -1169,29 +956,24 @@ export class Matterbridge extends EventEmitter {
1169
956
  this.log.debug(`Plugin ${plg}${plugin.name}${db} reachability timeout cleared`);
1170
957
  }
1171
958
  }
1172
- // Close the http server
1173
959
  if (this.httpServer) {
1174
960
  this.httpServer.close();
1175
961
  this.httpServer.removeAllListeners();
1176
962
  this.httpServer = undefined;
1177
963
  this.log.debug('Frontend http server closed successfully');
1178
964
  }
1179
- // Close the https server
1180
965
  if (this.httpsServer) {
1181
966
  this.httpsServer.close();
1182
967
  this.httpsServer.removeAllListeners();
1183
968
  this.httpsServer = undefined;
1184
969
  this.log.debug('Frontend https server closed successfully');
1185
970
  }
1186
- // Remove listeners from the express app
1187
971
  if (this.expressApp) {
1188
972
  this.expressApp.removeAllListeners();
1189
973
  this.expressApp = undefined;
1190
974
  this.log.debug('Frontend app closed successfully');
1191
975
  }
1192
- // Close the WebSocket server
1193
976
  if (this.webSocketServer) {
1194
- // Close all active connections
1195
977
  this.webSocketServer.clients.forEach((client) => {
1196
978
  if (client.readyState === WebSocket.OPEN) {
1197
979
  client.close();
@@ -1207,35 +989,26 @@ export class Matterbridge extends EventEmitter {
1207
989
  });
1208
990
  this.webSocketServer = undefined;
1209
991
  }
1210
- // Closing matter
1211
992
  await this.stopMatterServer();
1212
- // Closing matter storage
1213
993
  await this.stopMatterStorage();
1214
- // Remove the matterfilelogger
1215
994
  try {
1216
995
  Logger.removeLogger('matterfilelogger');
1217
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1218
996
  }
1219
997
  catch (error) {
1220
- // this.log.debug(`Error removing the matterfilelogger for file ${CYAN}${path.join(this.matterbridgeDirectory, this.matterLoggerFile)}${er}: ${error instanceof Error ? error.message : error}`);
1221
998
  }
1222
- // Serialize registeredDevices
1223
999
  if (this.nodeStorage && this.nodeContext) {
1224
1000
  this.log.info('Saving registered devices...');
1225
1001
  const serializedRegisteredDevices = [];
1226
1002
  this.devices.forEach(async (device) => {
1227
1003
  const serializedMatterbridgeDevice = device.serialize();
1228
- // this.log.info(`- ${serializedMatterbridgeDevice.deviceName}${rs}\n`, serializedMatterbridgeDevice);
1229
1004
  if (serializedMatterbridgeDevice)
1230
1005
  serializedRegisteredDevices.push(serializedMatterbridgeDevice);
1231
1006
  });
1232
1007
  await this.nodeContext.set('devices', serializedRegisteredDevices);
1233
1008
  this.log.info(`Saved registered devices (${serializedRegisteredDevices?.length})`);
1234
- // Clear nodeContext and nodeStorage (they just need 1000ms to write the data to disk)
1235
1009
  this.log.debug(`Closing node storage context for ${plg}Matterbridge${db}...`);
1236
1010
  await this.nodeContext.close();
1237
1011
  this.nodeContext = undefined;
1238
- // Clear nodeContext for each plugin (they just need 1000ms to write the data to disk)
1239
1012
  for (const plugin of this.plugins) {
1240
1013
  if (plugin.nodeContext) {
1241
1014
  this.log.debug(`Closing node storage context for plugin ${plg}${plugin.name}${db}...`);
@@ -1266,16 +1039,13 @@ export class Matterbridge extends EventEmitter {
1266
1039
  }
1267
1040
  else {
1268
1041
  if (message === 'shutting down with reset...') {
1269
- // Delete matter storage file
1270
1042
  this.log.info('Resetting Matterbridge commissioning information...');
1271
1043
  await fs.unlink(path.join(this.matterbridgeDirectory, this.matterStorageName));
1272
1044
  this.log.info('Reset done! Remove all paired devices from the controllers.');
1273
1045
  }
1274
1046
  if (message === 'shutting down with factory reset...') {
1275
- // Delete matter storage file
1276
1047
  this.log.info('Resetting Matterbridge commissioning information...');
1277
1048
  await fs.unlink(path.join(this.matterbridgeDirectory, this.matterStorageName));
1278
- // Delete node storage directory with its subdirectories
1279
1049
  this.log.info('Resetting Matterbridge storage...');
1280
1050
  await fs.rm(path.join(this.matterbridgeDirectory, this.nodeStorageName), { recursive: true });
1281
1051
  this.log.info('Factory reset done! Remove all paired devices from the controllers.');
@@ -1288,33 +1058,19 @@ export class Matterbridge extends EventEmitter {
1288
1058
  this.initialized = false;
1289
1059
  }
1290
1060
  }
1291
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1292
1061
  async addBridgedEndpoint(pluginName, device) {
1293
- // Nothing to do here
1294
1062
  }
1295
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1296
1063
  async removeBridgedEndpoint(pluginName, device) {
1297
- // Nothing to do here
1298
1064
  }
1299
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1300
1065
  async removeAllBridgedEndpoints(pluginName) {
1301
- // Nothing to do here
1302
1066
  }
1303
- /**
1304
- * Adds a bridged device to the Matterbridge.
1305
- * @param pluginName - The name of the plugin.
1306
- * @param device - The bridged device to add.
1307
- * @returns {Promise<void>} - A promise that resolves when the device is added.
1308
- */
1309
1067
  async addBridgedDevice(pluginName, device) {
1310
1068
  this.log.debug(`Adding bridged device ${dev}${device.deviceName}${db} (${zb}${device.name}${db}) for plugin ${plg}${pluginName}${db}`);
1311
- // Check if the plugin is registered
1312
1069
  const plugin = this.plugins.get(pluginName);
1313
1070
  if (!plugin) {
1314
1071
  this.log.error(`Error adding bridged device ${dev}${device.deviceName}${er} (${zb}${device.name}${er}) plugin ${plg}${pluginName}${er} not found`);
1315
1072
  return;
1316
1073
  }
1317
- // Register and add the device to matterbridge aggregator in bridge mode
1318
1074
  if (this.bridgeMode === 'bridge') {
1319
1075
  if (!this.matterAggregator) {
1320
1076
  this.log.error(`Adding bridged device ${dev}${device.deviceName}${er} (${zb}${device.name}${er}) for plugin ${plg}${pluginName}${er} error: matterAggregator not found`);
@@ -1322,11 +1078,8 @@ export class Matterbridge extends EventEmitter {
1322
1078
  }
1323
1079
  this.matterAggregator.addBridgedDevice(device);
1324
1080
  }
1325
- // The first time create the commissioning server and the aggregator for DynamicPlatform
1326
- // Register and add the device in childbridge mode
1327
1081
  if (this.bridgeMode === 'childbridge') {
1328
1082
  if (plugin.type === 'AccessoryPlatform') {
1329
- // Check if the plugin is locked with the commissioning server
1330
1083
  if (!plugin.locked) {
1331
1084
  plugin.locked = true;
1332
1085
  plugin.storageContext = await this.importCommissioningServerContext(plugin.name, device);
@@ -1340,7 +1093,6 @@ export class Matterbridge extends EventEmitter {
1340
1093
  }
1341
1094
  }
1342
1095
  if (plugin.type === 'DynamicPlatform') {
1343
- // Check if the plugin is locked with the commissioning server and the aggregator
1344
1096
  if (!plugin.locked) {
1345
1097
  plugin.locked = true;
1346
1098
  this.log.debug(`Creating commissioning server context for ${plg}${plugin.name}${db}`);
@@ -1348,7 +1100,7 @@ export class Matterbridge extends EventEmitter {
1348
1100
  this.log.debug(`Creating commissioning server for ${plg}${plugin.name}${db}`);
1349
1101
  plugin.commissioningServer = await this.createCommisioningServer(plugin.storageContext, plugin.name);
1350
1102
  this.log.debug(`Creating aggregator for plugin ${plg}${plugin.name}${db}`);
1351
- plugin.aggregator = await this.createMatterAggregator(plugin.storageContext, plugin.name); // Generate serialNumber and uniqueId
1103
+ plugin.aggregator = await this.createMatterAggregator(plugin.storageContext, plugin.name);
1352
1104
  this.log.debug(`Adding matter aggregator to commissioning server for plugin ${plg}${plugin.name}${db}`);
1353
1105
  plugin.commissioningServer.addDevice(plugin.aggregator);
1354
1106
  this.log.debug(`Adding commissioning server to matter server for plugin ${plg}${plugin.name}${db}`);
@@ -1361,25 +1113,16 @@ export class Matterbridge extends EventEmitter {
1361
1113
  plugin.registeredDevices++;
1362
1114
  if (plugin.addedDevices !== undefined)
1363
1115
  plugin.addedDevices++;
1364
- // Add the device to the DeviceManager
1365
1116
  this.devices.set(device);
1366
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}`);
1367
1118
  }
1368
- /**
1369
- * Removes a bridged device from the Matterbridge.
1370
- * @param pluginName - The name of the plugin.
1371
- * @param device - The device to be removed.
1372
- * @returns A Promise that resolves when the device is successfully removed.
1373
- */
1374
1119
  async removeBridgedDevice(pluginName, device) {
1375
1120
  this.log.debug(`Removing bridged device ${dev}${device.deviceName}${db} (${zb}${device.name}${db}) for plugin ${plg}${pluginName}${db}`);
1376
- // Check if the plugin is registered
1377
1121
  const plugin = this.plugins.get(pluginName);
1378
1122
  if (!plugin) {
1379
1123
  this.log.error(`Error removing bridged device ${dev}${device.deviceName}${er} (${zb}${device.name}${er}) for plugin ${plg}${pluginName}${er}: plugin not found`);
1380
1124
  return;
1381
1125
  }
1382
- // Remove the device from matterbridge aggregator in bridge mode
1383
1126
  if (this.bridgeMode === 'bridge') {
1384
1127
  if (!this.matterAggregator) {
1385
1128
  this.log.error(`Error removing bridged device ${dev}${device.deviceName}${er} (${zb}${device.name}${er}) for plugin ${plg}${pluginName}${er}: matterAggregator not found`);
@@ -1389,8 +1132,6 @@ export class Matterbridge extends EventEmitter {
1389
1132
  device.setBridgedDeviceReachability(false);
1390
1133
  device.getClusterServerById(BridgedDeviceBasicInformation.Cluster.id)?.triggerReachableChangedEvent({ reachableNewValue: false });
1391
1134
  }
1392
- // device.getClusterServerById(BridgedDeviceBasicInformation.Cluster.id)?.triggerShutDownEvent({});
1393
- // device.getClusterServerById(BridgedDeviceBasicInformation.Cluster.id)?.triggerLeaveEvent({});
1394
1135
  this.matterAggregator?.removeBridgedDevice(device);
1395
1136
  this.log.info(`Removed bridged device(${plugin.registeredDevices}/${plugin.addedDevices}) ${dev}${device.deviceName}${nf} (${zb}${device.name}${nf}) for plugin ${plg}${pluginName}${nf}`);
1396
1137
  if (plugin.registeredDevices !== undefined)
@@ -1398,7 +1139,6 @@ export class Matterbridge extends EventEmitter {
1398
1139
  if (plugin.addedDevices !== undefined)
1399
1140
  plugin.addedDevices--;
1400
1141
  }
1401
- // Remove the device in childbridge mode
1402
1142
  if (this.bridgeMode === 'childbridge') {
1403
1143
  if (plugin.type === 'AccessoryPlatform') {
1404
1144
  if (!plugin.commissioningServer) {
@@ -1422,22 +1162,14 @@ export class Matterbridge extends EventEmitter {
1422
1162
  plugin.registeredDevices--;
1423
1163
  if (plugin.addedDevices !== undefined)
1424
1164
  plugin.addedDevices--;
1425
- // Remove the commissioning server
1426
1165
  if (plugin.registeredDevices === 0 && plugin.addedDevices === 0 && plugin.commissioningServer) {
1427
1166
  this.matterServer?.removeCommissioningServer(plugin.commissioningServer);
1428
1167
  plugin.commissioningServer = undefined;
1429
1168
  this.log.info(`Removed commissioning server for plugin ${plg}${pluginName}${nf}`);
1430
1169
  }
1431
1170
  }
1432
- // Remove the device from the DeviceManager
1433
1171
  this.devices.remove(device);
1434
1172
  }
1435
- /**
1436
- * Removes all bridged devices associated with a specific plugin.
1437
- *
1438
- * @param pluginName - The name of the plugin.
1439
- * @returns A promise that resolves when all devices have been removed.
1440
- */
1441
1173
  async removeAllBridgedDevices(pluginName) {
1442
1174
  this.log.debug(`Removing all bridged devices for plugin ${plg}${pluginName}${db}`);
1443
1175
  this.devices.forEach(async (device) => {
@@ -1446,13 +1178,7 @@ export class Matterbridge extends EventEmitter {
1446
1178
  }
1447
1179
  });
1448
1180
  }
1449
- /**
1450
- * Starts the Matterbridge in bridge mode.
1451
- * @private
1452
- * @returns {Promise<void>} A promise that resolves when the Matterbridge is started.
1453
- */
1454
1181
  async startBridge() {
1455
- // Plugins are configured by a timer when matter server is started and plugin.configured is set to true
1456
1182
  if (!this.storageManager)
1457
1183
  throw new Error('No storage manager initialized');
1458
1184
  if (!this.matterbridgeContext)
@@ -1471,7 +1197,6 @@ export class Matterbridge extends EventEmitter {
1471
1197
  let failCount = 0;
1472
1198
  this.startMatterInterval = setInterval(async () => {
1473
1199
  for (const plugin of this.plugins) {
1474
- // new code to not start the bridge if one plugin is in error cause the controllers will delete the devices loosing all the configuration
1475
1200
  if (!plugin.enabled)
1476
1201
  continue;
1477
1202
  if (plugin.error) {
@@ -1496,18 +1221,15 @@ export class Matterbridge extends EventEmitter {
1496
1221
  clearInterval(this.startMatterInterval);
1497
1222
  this.startMatterInterval = undefined;
1498
1223
  this.log.debug('Cleared startMatterInterval interval for Matterbridge');
1499
- // Start the Matter server
1500
1224
  await this.startMatterServer();
1501
1225
  this.log.notice('Matter server started');
1502
- // Show the QR code for commissioning or log the already commissioned message
1503
1226
  await this.showCommissioningQRCode(this.commissioningServer, this.matterbridgeContext, this.nodeContext, 'Matterbridge');
1504
- // Configure the plugins
1505
1227
  this.configureTimeout = setTimeout(async () => {
1506
1228
  for (const plugin of this.plugins) {
1507
1229
  if (!plugin.enabled || !plugin.loaded || !plugin.started || plugin.error)
1508
1230
  continue;
1509
1231
  try {
1510
- await this.plugins.configure(plugin); // TODO No await do it in parallel
1232
+ await this.plugins.configure(plugin);
1511
1233
  }
1512
1234
  catch (error) {
1513
1235
  plugin.error = true;
@@ -1516,7 +1238,6 @@ export class Matterbridge extends EventEmitter {
1516
1238
  }
1517
1239
  this.wssSendRefreshRequired();
1518
1240
  }, 30 * 1000);
1519
- // Setting reachability to true
1520
1241
  this.reachabilityTimeout = setTimeout(() => {
1521
1242
  this.log.info(`Setting reachability to true for ${plg}Matterbridge${db}`);
1522
1243
  if (this.commissioningServer)
@@ -1526,14 +1247,7 @@ export class Matterbridge extends EventEmitter {
1526
1247
  }, 60 * 1000);
1527
1248
  }, 1000);
1528
1249
  }
1529
- /**
1530
- * Starts the Matterbridge in childbridge mode.
1531
- * @private
1532
- * @returns {Promise<void>} A promise that resolves when the Matterbridge is started.
1533
- */
1534
1250
  async startChildbridge() {
1535
- // Matterbridge.addBridgedDevice creates the commissionig servers and add the devices to the the commissioning server or to the aggregator
1536
- // Plugins are configured by a timer when matter server is started and plugin.configured is set to true
1537
1251
  if (!this.storageManager)
1538
1252
  throw new Error('No storage manager initialized');
1539
1253
  this.matterServer = this.createMatterServer(this.storageManager);
@@ -1543,7 +1257,6 @@ export class Matterbridge extends EventEmitter {
1543
1257
  this.startMatterInterval = setInterval(async () => {
1544
1258
  let allStarted = true;
1545
1259
  for (const plugin of this.plugins) {
1546
- // new code to not start the bridge if one plugin is in error cause the controllers will delete the devices loosing all the configuration
1547
1260
  if (!plugin.enabled)
1548
1261
  continue;
1549
1262
  if (plugin.error) {
@@ -1571,16 +1284,14 @@ export class Matterbridge extends EventEmitter {
1571
1284
  clearInterval(this.startMatterInterval);
1572
1285
  this.startMatterInterval = undefined;
1573
1286
  this.log.debug('Cleared startMatterInterval interval in childbridge mode');
1574
- // Start the Matter server
1575
1287
  await this.startMatterServer();
1576
1288
  this.log.notice('Matter server started');
1577
- // Configure the plugins
1578
1289
  this.configureTimeout = setTimeout(async () => {
1579
1290
  for (const plugin of this.plugins) {
1580
1291
  if (!plugin.enabled || !plugin.loaded || !plugin.started || plugin.error)
1581
1292
  continue;
1582
1293
  try {
1583
- await this.plugins.configure(plugin); // TODO No await do it in parallel
1294
+ await this.plugins.configure(plugin);
1584
1295
  }
1585
1296
  catch (error) {
1586
1297
  plugin.error = true;
@@ -1609,7 +1320,6 @@ export class Matterbridge extends EventEmitter {
1609
1320
  continue;
1610
1321
  }
1611
1322
  await this.showCommissioningQRCode(plugin.commissioningServer, plugin.storageContext, plugin.nodeContext, plugin.name);
1612
- // Setting reachability to true
1613
1323
  plugin.reachabilityTimeout = setTimeout(() => {
1614
1324
  this.log.info(`Setting reachability to true for ${plg}${plugin.name}${db}`);
1615
1325
  if (plugin.commissioningServer)
@@ -1622,11 +1332,6 @@ export class Matterbridge extends EventEmitter {
1622
1332
  }
1623
1333
  }, 1000);
1624
1334
  }
1625
- /**
1626
- * Starts the Matterbridge controller.
1627
- * @private
1628
- * @returns {Promise<void>} A promise that resolves when the Matterbridge is started.
1629
- */
1630
1335
  async startController() {
1631
1336
  if (!this.storageManager) {
1632
1337
  this.log.error('No storage manager initialized');
@@ -1689,7 +1394,7 @@ export class Matterbridge extends EventEmitter {
1689
1394
  const nodeId = await this.commissioningController.commissionNode(options);
1690
1395
  this.log.info(`Commissioning successfully done with nodeId: ${nodeId}`);
1691
1396
  this.log.info('ActiveSessionInformation:', this.commissioningController.getActiveSessionInformation());
1692
- } // (hasParameter('pairingcode'))
1397
+ }
1693
1398
  if (hasParameter('unpairall')) {
1694
1399
  this.log.info('***Commissioning controller unpairing all nodes...');
1695
1400
  const nodeIds = this.commissioningController.getCommissionedNodes();
@@ -1700,8 +1405,6 @@ export class Matterbridge extends EventEmitter {
1700
1405
  return;
1701
1406
  }
1702
1407
  if (hasParameter('discover')) {
1703
- // const discover = await this.commissioningController.discoverCommissionableDevices({ productId: 0x8000, deviceType: 0xfff1 });
1704
- // console.log(discover);
1705
1408
  }
1706
1409
  if (!this.commissioningController.isCommissioned()) {
1707
1410
  this.log.info('***Commissioning controller is not commissioned: use matterbridge -controller -pairingcode [pairingcode] to commission a device');
@@ -1742,12 +1445,10 @@ export class Matterbridge extends EventEmitter {
1742
1445
  },
1743
1446
  });
1744
1447
  node.logStructure();
1745
- // Get the interaction client
1746
1448
  this.log.info('Getting the interaction client');
1747
1449
  const interactionClient = await node.getInteractionClient();
1748
1450
  let cluster;
1749
1451
  let attributes;
1750
- // Log BasicInformationCluster
1751
1452
  cluster = BasicInformationCluster;
1752
1453
  attributes = await interactionClient.getMultipleAttributes({
1753
1454
  attributes: [{ clusterId: cluster.id }],
@@ -1757,7 +1458,6 @@ export class Matterbridge extends EventEmitter {
1757
1458
  attributes.forEach((attribute) => {
1758
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}`);
1759
1460
  });
1760
- // Log PowerSourceCluster
1761
1461
  cluster = PowerSourceCluster;
1762
1462
  attributes = await interactionClient.getMultipleAttributes({
1763
1463
  attributes: [{ clusterId: cluster.id }],
@@ -1767,7 +1467,6 @@ export class Matterbridge extends EventEmitter {
1767
1467
  attributes.forEach((attribute) => {
1768
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}`);
1769
1469
  });
1770
- // Log ThreadNetworkDiagnostics
1771
1470
  cluster = ThreadNetworkDiagnosticsCluster;
1772
1471
  attributes = await interactionClient.getMultipleAttributes({
1773
1472
  attributes: [{ clusterId: cluster.id }],
@@ -1777,7 +1476,6 @@ export class Matterbridge extends EventEmitter {
1777
1476
  attributes.forEach((attribute) => {
1778
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}`);
1779
1478
  });
1780
- // Log SwitchCluster
1781
1479
  cluster = SwitchCluster;
1782
1480
  attributes = await interactionClient.getMultipleAttributes({
1783
1481
  attributes: [{ clusterId: cluster.id }],
@@ -1798,15 +1496,6 @@ export class Matterbridge extends EventEmitter {
1798
1496
  this.log.info('Subscribed to all attributes and events');
1799
1497
  }
1800
1498
  }
1801
- /** ***********************************************************************************************************************************/
1802
- /** Matter.js methods */
1803
- /** ***********************************************************************************************************************************/
1804
- /**
1805
- * Starts the matter storage process based on the specified storage type and name.
1806
- * @param {string} storageType - The type of storage to start (e.g., 'disk', 'json').
1807
- * @param {string} storageName - The name of the storage file.
1808
- * @returns {Promise<void>} - A promise that resolves when the storage process is started.
1809
- */
1810
1499
  async startMatterStorage(storageType, storageName) {
1811
1500
  this.log.debug(`Starting matter ${storageType} storage ${CYAN}${storageName}${db}`);
1812
1501
  if (storageType === 'disk') {
@@ -1852,12 +1541,6 @@ export class Matterbridge extends EventEmitter {
1852
1541
  this.log.debug(`Creating commissioning server context for ${plg}Matterbridge${db}`);
1853
1542
  this.matterbridgeContext = await this.createCommissioningServerContext('Matterbridge', 'Matterbridge', DeviceTypes.AGGREGATOR.code, 0xfff1, 'Matterbridge', 0x8000, 'Matterbridge aggregator');
1854
1543
  }
1855
- /**
1856
- * Makes a backup copy of the specified matter JSON storage file.
1857
- *
1858
- * @param storageName - The name of the JSON storage file to be backed up.
1859
- * @param backupName - The name of the backup file to be created.
1860
- */
1861
1544
  async backupMatterStorage(storageName, backupName) {
1862
1545
  try {
1863
1546
  this.log.debug(`Making backup copy of ${storageName}`);
@@ -1878,12 +1561,6 @@ export class Matterbridge extends EventEmitter {
1878
1561
  }
1879
1562
  }
1880
1563
  }
1881
- /**
1882
- * Restore the specified matter JSON storage file.
1883
- *
1884
- * @param backupName - The name of the backup file to restore from.
1885
- * @param storageName - The name of the JSON storage file to restored.
1886
- */
1887
1564
  async restoreMatterStorage(backupName, storageName) {
1888
1565
  try {
1889
1566
  this.log.notice(`Restoring the backup copy of ${storageName}`);
@@ -1904,10 +1581,6 @@ export class Matterbridge extends EventEmitter {
1904
1581
  }
1905
1582
  }
1906
1583
  }
1907
- /**
1908
- * Stops the matter storage.
1909
- * @returns {Promise<void>} A promise that resolves when the storage is stopped.
1910
- */
1911
1584
  async stopMatterStorage() {
1912
1585
  this.log.debug('Stopping storage');
1913
1586
  await this.storageManager?.close();
@@ -1916,14 +1589,8 @@ export class Matterbridge extends EventEmitter {
1916
1589
  this.matterbridgeContext = undefined;
1917
1590
  this.mattercontrollerContext = undefined;
1918
1591
  }
1919
- /**
1920
- * Creates a Matter server using the provided storage manager and the provided mdnsInterface.
1921
- * @param storageManager The storage manager to be used by the Matter server.
1922
- *
1923
- */
1924
1592
  createMatterServer(storageManager) {
1925
1593
  this.log.debug('Creating matter server');
1926
- // Validate mdnsInterface
1927
1594
  if (this.mdnsInterface) {
1928
1595
  const networkInterfaces = os.networkInterfaces();
1929
1596
  const availableInterfaces = Object.keys(networkInterfaces);
@@ -1939,10 +1606,6 @@ export class Matterbridge extends EventEmitter {
1939
1606
  this.log.debug(`Created matter server with mdnsInterface: ${this.mdnsInterface ?? 'all available interfaces'}`);
1940
1607
  return matterServer;
1941
1608
  }
1942
- /**
1943
- * Starts the Matter server.
1944
- * If the Matter server is not initialized, it logs an error and performs cleanup.
1945
- */
1946
1609
  async startMatterServer() {
1947
1610
  if (!this.matterServer) {
1948
1611
  this.log.error('No matter server initialized');
@@ -1952,11 +1615,7 @@ export class Matterbridge extends EventEmitter {
1952
1615
  this.log.debug('Starting matter server...');
1953
1616
  await this.matterServer.start();
1954
1617
  this.log.debug('Started matter server');
1955
- // this.commissioningServer?.getRootEndpoint() && logEndpoint(this.commissioningServer?.getRootEndpoint());
1956
1618
  }
1957
- /**
1958
- * Stops the Matter server, commissioningServer and commissioningController.
1959
- */
1960
1619
  async stopMatterServer() {
1961
1620
  this.log.debug('Stopping matter commissioningServer');
1962
1621
  await this.commissioningServer?.close();
@@ -1970,78 +1629,22 @@ export class Matterbridge extends EventEmitter {
1970
1629
  this.matterAggregator = undefined;
1971
1630
  this.matterServer = undefined;
1972
1631
  }
1973
- /**
1974
- * Creates a Matter Aggregator.
1975
- * @param {StorageContext} context - The storage context.
1976
- * @returns {Aggregator} - The created Matter Aggregator.
1977
- */
1978
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1979
1632
  async createMatterAggregator(context, pluginName) {
1980
- /*
1981
- const random = randomBytes(8).toString('hex');
1982
- await context.set('aggregatorSerialNumber', await context.get('aggregatorSerialNumber', random));
1983
- await context.set('aggregatorUniqueId', await context.get('aggregatorUniqueId', random));
1984
-
1985
- this.log.debug(`Creating matter aggregator for plugin ${plg}${pluginName}${db} with uniqueId ${await context.get<string>('aggregatorUniqueId')} serialNumber ${await context.get<string>('aggregatorSerialNumber')}`);
1986
- this.log.debug(`Creating matter aggregator for plugin ${plg}${pluginName}${db} with softwareVersion ${await context.get<number>('softwareVersion', 1)} softwareVersionString ${await context.get<string>('softwareVersionString', '1.0.0')}`);
1987
- this.log.debug(`Creating matter aggregator for plugin ${plg}${pluginName}${db} with hardwareVersion ${await context.get<number>('hardwareVersion', 1)} hardwareVersionString ${await context.get<string>('hardwareVersionString', '1.0.0')}`);
1988
- */
1989
1633
  const matterAggregator = new Aggregator();
1990
- /*
1991
- matterAggregator.addClusterServer(
1992
- ClusterServer(
1993
- BasicInformationCluster,
1994
- {
1995
- dataModelRevision: 1,
1996
- location: 'FR',
1997
- vendorId: VendorId(0xfff1),
1998
- vendorName: 'Matterbridge',
1999
- productId: 0x8000,
2000
- productName: 'Matterbridge aggregator',
2001
- productLabel: 'Matterbridge aggregator',
2002
- nodeLabel: 'Matterbridge aggregator',
2003
- serialNumber: await context.get<string>('aggregatorSerialNumber'),
2004
- uniqueId: await context.get<string>('aggregatorUniqueId'),
2005
- softwareVersion: await context.get<number>('softwareVersion', 1),
2006
- softwareVersionString: await context.get<string>('softwareVersionString', '1.0.0'),
2007
- hardwareVersion: await context.get<number>('hardwareVersion', 1),
2008
- hardwareVersionString: await context.get<string>('hardwareVersionString', '1.0.0'),
2009
- reachable: true,
2010
- capabilityMinima: { caseSessionsPerFabric: 3, subscriptionsPerFabric: 3 },
2011
- specificationVersion: Specification.SPECIFICATION_VERSION,
2012
- maxPathsPerInvoke: 1,
2013
- },
2014
- {},
2015
- {
2016
- startUp: true,
2017
- shutDown: true,
2018
- leave: true,
2019
- reachableChanged: true,
2020
- },
2021
- ),
2022
- );
2023
- */
2024
1634
  return matterAggregator;
2025
1635
  }
2026
- /**
2027
- * Creates a matter commissioning server.
2028
- *
2029
- * @param {StorageContext} context - The storage context.
2030
- * @param {string} pluginName - The name of the commissioning server.
2031
- * @returns {CommissioningServer} The created commissioning server.
2032
- */
2033
1636
  async createCommisioningServer(context, pluginName) {
2034
1637
  this.log.debug(`Creating matter commissioning server for plugin ${plg}${pluginName}${db}`);
2035
1638
  const deviceName = await context.get('deviceName');
2036
1639
  const deviceType = await context.get('deviceType');
2037
1640
  const vendorId = await context.get('vendorId');
2038
- const vendorName = await context.get('vendorName'); // Home app = Manufacturer
1641
+ const vendorName = await context.get('vendorName');
2039
1642
  const productId = await context.get('productId');
2040
- const productName = await context.get('productName'); // Home app = Model
1643
+ const productName = await context.get('productName');
2041
1644
  const serialNumber = await context.get('serialNumber');
2042
1645
  const uniqueId = await context.get('uniqueId');
2043
1646
  const softwareVersion = await context.get('softwareVersion', 1);
2044
- const softwareVersionString = await context.get('softwareVersionString', '1.0.0'); // Home app = Firmware Revision
1647
+ const softwareVersionString = await context.get('softwareVersionString', '1.0.0');
2045
1648
  const hardwareVersion = await context.get('hardwareVersion', 1);
2046
1649
  const hardwareVersionString = await context.get('hardwareVersionString', '1.0.0');
2047
1650
  this.log.debug(`Creating matter commissioning server for plugin ${plg}${pluginName}${db} with deviceName '${deviceName}' deviceType ${deviceType}(0x${deviceType.toString(16).padStart(4, '0')})`);
@@ -2049,7 +1652,6 @@ export class Matterbridge extends EventEmitter {
2049
1652
  this.log.debug(`Creating matter commissioning server for plugin ${plg}${pluginName}${db} with softwareVersion ${softwareVersion} softwareVersionString ${softwareVersionString}`);
2050
1653
  this.log.debug(`Creating matter commissioning server for plugin ${plg}${pluginName}${db} with hardwareVersion ${hardwareVersion} hardwareVersionString ${hardwareVersionString}`);
2051
1654
  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} `);
2052
- // Validate ipv4address
2053
1655
  if (this.ipv4address) {
2054
1656
  const networkInterfaces = os.networkInterfaces();
2055
1657
  const availableAddresses = Object.values(networkInterfaces)
@@ -2064,7 +1666,6 @@ export class Matterbridge extends EventEmitter {
2064
1666
  this.log.info(`Using ipv4address '${this.ipv4address}' for the Matter commissioning server.`);
2065
1667
  }
2066
1668
  }
2067
- // Validate ipv6address
2068
1669
  if (this.ipv6address) {
2069
1670
  const networkInterfaces = os.networkInterfaces();
2070
1671
  const availableAddresses = Object.values(networkInterfaces)
@@ -2095,7 +1696,7 @@ export class Matterbridge extends EventEmitter {
2095
1696
  nodeLabel: productName,
2096
1697
  productLabel: productName,
2097
1698
  softwareVersion,
2098
- softwareVersionString, // Home app = Firmware Revision
1699
+ softwareVersionString,
2099
1700
  hardwareVersion,
2100
1701
  hardwareVersionString,
2101
1702
  uniqueId,
@@ -2191,24 +1792,6 @@ export class Matterbridge extends EventEmitter {
2191
1792
  commissioningServer.addCommandHandler('testEventTrigger', async ({ request: { enableKey, eventTrigger } }) => this.log.info(`testEventTrigger called on GeneralDiagnostic cluster: ${enableKey} ${eventTrigger}`));
2192
1793
  return commissioningServer;
2193
1794
  }
2194
- /**
2195
- * Creates a commissioning server storage context.
2196
- *
2197
- * @param pluginName - The name of the plugin.
2198
- * @param deviceName - The name of the device.
2199
- * @param deviceType - The type of the device.
2200
- * @param vendorId - The vendor ID.
2201
- * @param vendorName - The vendor name.
2202
- * @param productId - The product ID.
2203
- * @param productName - The product name.
2204
- * @param serialNumber - The serial number of the device (optional).
2205
- * @param uniqueId - The unique ID of the device (optional).
2206
- * @param softwareVersion - The software version of the device (optional).
2207
- * @param softwareVersionString - The software version string of the device (optional).
2208
- * @param hardwareVersion - The hardware version of the device (optional).
2209
- * @param hardwareVersionString - The hardware version string of the device (optional).
2210
- * @returns The storage context for the commissioning server.
2211
- */
2212
1795
  async createCommissioningServerContext(pluginName, deviceName, deviceType, vendorId, vendorName, productId, productName) {
2213
1796
  if (!this.storageManager)
2214
1797
  throw new Error('No storage manager initialized');
@@ -2236,13 +1819,6 @@ export class Matterbridge extends EventEmitter {
2236
1819
  this.log.debug(`- hardwareVersion: ${await storageContext.get('hardwareVersion')} hardwareVersionString: ${await storageContext.get('hardwareVersionString')}`);
2237
1820
  return storageContext;
2238
1821
  }
2239
- /**
2240
- * Imports the commissioning server context for a specific plugin and device.
2241
- * @param pluginName - The name of the plugin.
2242
- * @param device - The MatterbridgeDevice object representing the device.
2243
- * @returns The commissioning server context.
2244
- * @throws Error if the BasicInformationCluster is not found.
2245
- */
2246
1822
  async importCommissioningServerContext(pluginName, device) {
2247
1823
  this.log.debug(`Importing matter commissioning server storage context from device for ${plg}${pluginName}${db}`);
2248
1824
  const basic = device.getClusterServer(BasicInformationCluster);
@@ -2277,14 +1853,6 @@ export class Matterbridge extends EventEmitter {
2277
1853
  this.log.debug(`- hardwareVersion: ${await storageContext.get('hardwareVersion')} hardwareVersionString: ${await storageContext.get('hardwareVersionString')}`);
2278
1854
  return storageContext;
2279
1855
  }
2280
- /**
2281
- * Shows the commissioning server QR code for a given plugin.
2282
- * @param {CommissioningServer} commissioningServer - The commissioning server instance.
2283
- * @param {StorageContext} storageContext - The storage context instance.
2284
- * @param {NodeStorage} nodeContext - The node storage instance.
2285
- * @param {string} pluginName - The name of the plugin of Matterbridge in bridge mode.
2286
- * @returns {Promise<void>} - A promise that resolves when the QR code is shown.
2287
- */
2288
1856
  async showCommissioningQRCode(commissioningServer, storageContext, nodeContext, pluginName) {
2289
1857
  if (!commissioningServer || !storageContext || !nodeContext || !pluginName) {
2290
1858
  this.log.error(`showCommissioningQRCode error: commissioningServer: ${!commissioningServer} storageContext: ${!storageContext} nodeContext: ${!nodeContext} pluginName: ${pluginName}`);
@@ -2295,8 +1863,7 @@ export class Matterbridge extends EventEmitter {
2295
1863
  const { qrPairingCode, manualPairingCode } = commissioningServer.getPairingCode();
2296
1864
  const QrCode = new QrCodeSchema();
2297
1865
  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`);
2298
- // eslint-disable-next-line no-console
2299
- if (this.log.logLevel === "debug" /* LogLevel.DEBUG */ || this.log.logLevel === "info" /* LogLevel.INFO */)
1866
+ if (this.log.logLevel === "debug" || this.log.logLevel === "info")
2300
1867
  console.log(`${QrCode.encode(qrPairingCode)}\n`);
2301
1868
  this.log.info(`${plg}${pluginName}${nf} \n\nqrPairingCode: ${qrPairingCode} \n\nManual pairing code: ${manualPairingCode}\n`);
2302
1869
  if (pluginName === 'Matterbridge') {
@@ -2343,12 +1910,6 @@ export class Matterbridge extends EventEmitter {
2343
1910
  }
2344
1911
  this.wssSendRefreshRequired();
2345
1912
  }
2346
- /**
2347
- * Sanitizes the fabric information by converting bigint properties to string cause res.json doesn't know bigint.
2348
- *
2349
- * @param fabricInfo - The array of exposed fabric information objects.
2350
- * @returns An array of sanitized exposed fabric information objects.
2351
- */
2352
1913
  sanitizeFabricInformations(fabricInfo) {
2353
1914
  return fabricInfo.map((info) => {
2354
1915
  return {
@@ -2362,12 +1923,6 @@ export class Matterbridge extends EventEmitter {
2362
1923
  };
2363
1924
  });
2364
1925
  }
2365
- /**
2366
- * Sanitizes the session information by converting bigint properties to string.
2367
- *
2368
- * @param sessionInfo - The array of session information objects.
2369
- * @returns An array of sanitized session information objects.
2370
- */
2371
1926
  sanitizeSessionInformation(sessionInfo) {
2372
1927
  return sessionInfo
2373
1928
  .filter((session) => session.isPeerActive)
@@ -2395,12 +1950,6 @@ export class Matterbridge extends EventEmitter {
2395
1950
  };
2396
1951
  });
2397
1952
  }
2398
- /**
2399
- * Sets the reachability of a commissioning server and trigger.
2400
- *
2401
- * @param {CommissioningServer} commissioningServer - The commissioning server to set the reachability for.
2402
- * @param {boolean} reachable - The new reachability status.
2403
- */
2404
1953
  setCommissioningServerReachability(commissioningServer, reachable) {
2405
1954
  const basicInformationCluster = commissioningServer?.getRootClusterServer(BasicInformationCluster);
2406
1955
  if (basicInformationCluster && basicInformationCluster.attributes.reachable !== undefined)
@@ -2408,11 +1957,6 @@ export class Matterbridge extends EventEmitter {
2408
1957
  if (basicInformationCluster && basicInformationCluster.triggerReachableChangedEvent)
2409
1958
  basicInformationCluster.triggerReachableChangedEvent({ reachableNewValue: reachable });
2410
1959
  }
2411
- /**
2412
- * Sets the reachability of the specified matter aggregator and its bridged devices and trigger.
2413
- * @param {Aggregator} matterAggregator - The matter aggregator to set the reachability for.
2414
- * @param {boolean} reachable - A boolean indicating the reachability status to set.
2415
- */
2416
1960
  setAggregatorReachability(matterAggregator, reachable) {
2417
1961
  const basicInformationCluster = matterAggregator.getClusterServer(BasicInformationCluster);
2418
1962
  if (basicInformationCluster && basicInformationCluster.attributes.reachable !== undefined)
@@ -2425,12 +1969,6 @@ export class Matterbridge extends EventEmitter {
2425
1969
  device.getClusterServer(BridgedDeviceBasicInformationCluster)?.triggerReachableChangedEvent({ reachableNewValue: reachable });
2426
1970
  });
2427
1971
  }
2428
- /**
2429
- * Sets the reachability of a device and trigger.
2430
- *
2431
- * @param {MatterbridgeDevice} device - The device to set the reachability for.
2432
- * @param {boolean} reachable - The new reachability status of the device.
2433
- */
2434
1972
  setDeviceReachability(device, reachable) {
2435
1973
  const basicInformationCluster = device.getClusterServer(BasicInformationCluster);
2436
1974
  if (basicInformationCluster && basicInformationCluster.attributes.reachable !== undefined)
@@ -2479,10 +2017,6 @@ export class Matterbridge extends EventEmitter {
2479
2017
  }
2480
2018
  return vendorName;
2481
2019
  };
2482
- /**
2483
- * Retrieves the base registered plugins sanitized for res.json().
2484
- * @returns {BaseRegisteredPlugin[]} A promise that resolves to an array of BaseRegisteredPlugin objects.
2485
- */
2486
2020
  async getBaseRegisteredPlugins() {
2487
2021
  const baseRegisteredPlugins = [];
2488
2022
  for (const plugin of this.plugins) {
@@ -2514,36 +2048,13 @@ export class Matterbridge extends EventEmitter {
2514
2048
  }
2515
2049
  return baseRegisteredPlugins;
2516
2050
  }
2517
- /**
2518
- * Spawns a child process with the given command and arguments.
2519
- * @param {string} command - The command to execute.
2520
- * @param {string[]} args - The arguments to pass to the command (default: []).
2521
- * @returns {Promise<boolean>} A promise that resolves when the child process exits successfully, or rejects if there is an error.
2522
- */
2523
2051
  async spawnCommand(command, args = []) {
2524
- /*
2525
- npm > npm.cmd on windows
2526
- cmd.exe ['dir'] on windows
2527
- await this.spawnCommand('npm', ['install', '-g', 'matterbridge']);
2528
- process.on('unhandledRejection', (reason, promise) => {
2529
- this.log.error('Unhandled Rejection at:', promise, 'reason:', reason);
2530
- });
2531
-
2532
- spawn - [14:27:21.125] [Matterbridge:spawn]: changed 38 packages in 4s
2533
- spawn - [14:27:21.125] [Matterbridge:spawn]: 10 packages are looking for funding run `npm fund` for details
2534
- debug - [14:27:21.131] [Matterbridge]: Child process exited with code 0 and signal null
2535
- debug - [14:27:21.131] [Matterbridge]: Child process stdio streams have closed with code 0
2536
- */
2537
2052
  const cmdLine = command + ' ' + args.join(' ');
2538
2053
  if (process.platform === 'win32' && command === 'npm') {
2539
- // Must be spawn('cmd.exe', ['/c', 'npm -g install <package>']);
2540
2054
  const argstring = 'npm ' + args.join(' ');
2541
2055
  args.splice(0, args.length, '/c', argstring);
2542
2056
  command = 'cmd.exe';
2543
2057
  }
2544
- // Decide when using sudo on linux
2545
- // When you need sudo: Spawn stderr: npm error Error: EACCES: permission denied
2546
- // When you don't need sudo: Failed to start child process "npm install -g matterbridge-eve-door": spawn sudo ENOENT
2547
2058
  if (hasParameter('sudo') || (process.platform === 'linux' && command === 'npm' && !hasParameter('docker') && !hasParameter('nosudo'))) {
2548
2059
  args.unshift(command);
2549
2060
  command = 'sudo';
@@ -2601,102 +2112,55 @@ export class Matterbridge extends EventEmitter {
2601
2112
  }
2602
2113
  });
2603
2114
  }
2604
- /**
2605
- * Sends a WebSocket message to all connected clients.
2606
- *
2607
- * @param {string} level - The logger level of the message: debug info notice warn error fatal...
2608
- * @param {string} time - The time string of the message
2609
- * @param {string} name - The logger name of the message
2610
- * @param {string} message - The content of the message.
2611
- */
2612
2115
  wssSendMessage(level, time, name, message) {
2613
2116
  if (!level || !time || !name || !message)
2614
2117
  return;
2615
- // Remove ANSI escape codes from the message
2616
- // eslint-disable-next-line no-control-regex
2617
2118
  message = message.replace(/\x1B\[[0-9;]*[m|s|u|K]/g, '');
2618
- // Remove leading asterisks from the message
2619
2119
  message = message.replace(/^\*+/, '');
2620
- // Replace all occurrences of \t and \n
2621
2120
  message = message.replace(/[\t\n]/g, '');
2622
- // Remove non-printable characters
2623
- // eslint-disable-next-line no-control-regex
2624
2121
  message = message.replace(/[\x00-\x1F\x7F]/g, '');
2625
- // Replace all occurrences of \" with "
2626
2122
  message = message.replace(/\\"/g, '"');
2627
- // Define the maximum allowed length for continuous characters without a space
2628
2123
  const maxContinuousLength = 100;
2629
2124
  const keepStartLength = 20;
2630
2125
  const keepEndLength = 20;
2631
- // Split the message into words
2632
2126
  message = message
2633
2127
  .split(' ')
2634
2128
  .map((word) => {
2635
- // If the word length exceeds the max continuous length, insert spaces and truncate
2636
2129
  if (word.length > maxContinuousLength) {
2637
2130
  return word.slice(0, keepStartLength) + ' ... ' + word.slice(-keepEndLength);
2638
2131
  }
2639
2132
  return word;
2640
2133
  })
2641
2134
  .join(' ');
2642
- // Send the message to all connected clients
2643
2135
  this.webSocketServer?.clients.forEach((client) => {
2644
2136
  if (client.readyState === WebSocket.OPEN) {
2645
2137
  client.send(JSON.stringify({ id: WS_ID_LOG, src: 'Matterbridge', level, time, name, message }));
2646
2138
  }
2647
2139
  });
2648
2140
  }
2649
- /**
2650
- * Sends a need to refresh WebSocket message to all connected clients.
2651
- *
2652
- */
2653
2141
  wssSendRefreshRequired() {
2654
2142
  this.matterbridgeInformation.refreshRequired = true;
2655
- // Send the message to all connected clients
2656
2143
  this.webSocketServer?.clients.forEach((client) => {
2657
2144
  if (client.readyState === WebSocket.OPEN) {
2658
2145
  client.send(JSON.stringify({ id: WS_ID_REFRESH_NEEDED, src: 'Matterbridge', dst: 'Matterbridge', method: 'refresh_required', params: {} }));
2659
2146
  }
2660
2147
  });
2661
2148
  }
2662
- /**
2663
- * Sends a need to restart WebSocket message to all connected clients.
2664
- *
2665
- */
2666
2149
  wssSendRestartRequired() {
2667
2150
  this.matterbridgeInformation.restartRequired = true;
2668
- // Send the message to all connected clients
2669
2151
  this.webSocketServer?.clients.forEach((client) => {
2670
2152
  if (client.readyState === WebSocket.OPEN) {
2671
2153
  client.send(JSON.stringify({ id: WS_ID_RESTART_NEEDED, src: 'Matterbridge', dst: 'Matterbridge', method: 'restart_required', params: {} }));
2672
2154
  }
2673
2155
  });
2674
2156
  }
2675
- /**
2676
- * Initializes the frontend of Matterbridge.
2677
- *
2678
- * @param port The port number to run the frontend server on. Default is 8283.
2679
- */
2680
2157
  async initializeFrontend(port = 8283) {
2681
2158
  let initializeError = false;
2682
2159
  this.log.debug(`Initializing the frontend ${hasParameter('ssl') ? 'https' : 'http'} server on port ${YELLOW}${port}${db}`);
2683
- // Create the express app that serves the frontend
2684
2160
  this.expressApp = express();
2685
- // Log all requests to the server for debugging
2686
- /*
2687
- if (hasParameter('homedir')) {
2688
- this.expressApp.use((req, res, next) => {
2689
- this.log.debug(`Received request on expressApp: ${req.method} ${req.url}`);
2690
- next();
2691
- });
2692
- }
2693
- */
2694
- // Serve static files from '/static' endpoint
2695
2161
  this.expressApp.use(express.static(path.join(this.rootDirectory, 'frontend/build')));
2696
2162
  if (!hasParameter('ssl')) {
2697
- // Create an HTTP server and attach the express app
2698
2163
  this.httpServer = createServer(this.expressApp);
2699
- // Listen on the specified port
2700
2164
  if (hasParameter('ingress')) {
2701
2165
  this.httpServer.listen(port, '0.0.0.0', () => {
2702
2166
  this.log.info(`The frontend http server is listening on ${UNDERLINE}http://0.0.0.0:${port}${UNDERLINEOFF}${rs}`);
@@ -2710,7 +2174,6 @@ export class Matterbridge extends EventEmitter {
2710
2174
  this.log.info(`The frontend http server is listening on ${UNDERLINE}http://[${this.systemInformation.ipv6Address}]:${port}${UNDERLINEOFF}${rs}`);
2711
2175
  });
2712
2176
  }
2713
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
2714
2177
  this.httpServer.on('error', (error) => {
2715
2178
  this.log.error(`Frontend http server error listening on ${port}`);
2716
2179
  switch (error.code) {
@@ -2726,7 +2189,6 @@ export class Matterbridge extends EventEmitter {
2726
2189
  });
2727
2190
  }
2728
2191
  else {
2729
- // Load the SSL certificate, the private key and optionally the CA certificate
2730
2192
  let cert;
2731
2193
  try {
2732
2194
  cert = await fs.readFile(path.join(this.matterbridgeDirectory, 'certs/cert.pem'), 'utf8');
@@ -2754,9 +2216,7 @@ export class Matterbridge extends EventEmitter {
2754
2216
  this.log.info(`CA certificate file ${path.join(this.matterbridgeDirectory, 'certs/ca.pem')} not loaded: ${error}`);
2755
2217
  }
2756
2218
  const serverOptions = { cert, key, ca };
2757
- // Create an HTTPS server with the SSL certificate and private key (ca is optional) and attach the express app
2758
2219
  this.httpsServer = https.createServer(serverOptions, this.expressApp);
2759
- // Listen on the specified port
2760
2220
  if (hasParameter('ingress')) {
2761
2221
  this.httpsServer.listen(port, '0.0.0.0', () => {
2762
2222
  this.log.info(`The frontend https server is listening on ${UNDERLINE}https://0.0.0.0:${port}${UNDERLINEOFF}${rs}`);
@@ -2770,7 +2230,6 @@ export class Matterbridge extends EventEmitter {
2770
2230
  this.log.info(`The frontend https server is listening on ${UNDERLINE}https://[${this.systemInformation.ipv6Address}]:${port}${UNDERLINEOFF}${rs}`);
2771
2231
  });
2772
2232
  }
2773
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
2774
2233
  this.httpsServer.on('error', (error) => {
2775
2234
  this.log.error(`Frontend https server error listening on ${port}`);
2776
2235
  switch (error.code) {
@@ -2787,13 +2246,12 @@ export class Matterbridge extends EventEmitter {
2787
2246
  }
2788
2247
  if (initializeError)
2789
2248
  return;
2790
- // Createe a WebSocket server and attach it to the http or https server
2791
2249
  const wssPort = port;
2792
2250
  const wssHost = hasParameter('ssl') ? `wss://${this.systemInformation.ipv4Address}:${wssPort}` : `ws://${this.systemInformation.ipv4Address}:${wssPort}`;
2793
2251
  this.webSocketServer = new WebSocketServer(hasParameter('ssl') ? { server: this.httpsServer } : { server: this.httpServer });
2794
2252
  this.webSocketServer.on('connection', (ws, request) => {
2795
2253
  const clientIp = request.socket.remoteAddress;
2796
- AnsiLogger.setGlobalCallback(this.wssSendMessage.bind(this), "debug" /* LogLevel.DEBUG */);
2254
+ AnsiLogger.setGlobalCallback(this.wssSendMessage.bind(this), "debug");
2797
2255
  this.log.info(`WebSocketServer client "${clientIp}" connected to Matterbridge`);
2798
2256
  ws.on('message', (message) => {
2799
2257
  this.log.debug(`WebSocket client message: ${message}`);
@@ -2826,7 +2284,6 @@ export class Matterbridge extends EventEmitter {
2826
2284
  this.webSocketServer.on('error', (ws, error) => {
2827
2285
  this.log.error(`WebSocketServer error: ${error}`);
2828
2286
  });
2829
- // Endpoint to validate login code
2830
2287
  this.expressApp.post('/api/login', express.json(), async (req, res) => {
2831
2288
  const { password } = req.body;
2832
2289
  this.log.debug('The frontend sent /api/login', password);
@@ -2845,14 +2302,12 @@ export class Matterbridge extends EventEmitter {
2845
2302
  this.log.warn('/api/login error wrong password');
2846
2303
  res.json({ valid: false });
2847
2304
  }
2848
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
2849
2305
  }
2850
2306
  catch (error) {
2851
2307
  this.log.error('/api/login error getting password');
2852
2308
  res.json({ valid: false });
2853
2309
  }
2854
2310
  });
2855
- // Endpoint to provide settings
2856
2311
  this.expressApp.get('/api/settings', express.json(), async (req, res) => {
2857
2312
  this.log.debug('The frontend sent /api/settings');
2858
2313
  this.matterbridgeInformation.bridgeMode = this.bridgeMode;
@@ -2873,17 +2328,13 @@ export class Matterbridge extends EventEmitter {
2873
2328
  this.matterbridgeInformation.matterbridgeSessionInformations = Array.from(this.matterbridgeSessionInformations.values());
2874
2329
  this.matterbridgeInformation.profile = this.profile;
2875
2330
  const response = { wssHost, ssl: hasParameter('ssl'), systemInformation: this.systemInformation, matterbridgeInformation: this.matterbridgeInformation };
2876
- // this.log.debug('Response:', debugStringify(response));
2877
2331
  res.json(response);
2878
2332
  });
2879
- // Endpoint to provide plugins
2880
2333
  this.expressApp.get('/api/plugins', async (req, res) => {
2881
2334
  this.log.debug('The frontend sent /api/plugins');
2882
2335
  const response = await this.getBaseRegisteredPlugins();
2883
- // this.log.debug('Response:', debugStringify(response));
2884
2336
  res.json(response);
2885
2337
  });
2886
- // Endpoint to provide devices
2887
2338
  this.expressApp.get('/api/devices', (req, res) => {
2888
2339
  this.log.debug('The frontend sent /api/devices');
2889
2340
  const devices = [];
@@ -2916,10 +2367,8 @@ export class Matterbridge extends EventEmitter {
2916
2367
  cluster: cluster,
2917
2368
  });
2918
2369
  });
2919
- // this.log.debug('Response:', debugStringify(data));
2920
2370
  res.json(devices);
2921
2371
  });
2922
- // Endpoint to provide the cluster servers of the devices
2923
2372
  this.expressApp.get('/api/devices_clusters/:selectedPluginName/:selectedDeviceEndpoint', (req, res) => {
2924
2373
  const selectedPluginName = req.params.selectedPluginName;
2925
2374
  const selectedDeviceEndpoint = parseInt(req.params.selectedDeviceEndpoint, 10);
@@ -2939,7 +2388,6 @@ export class Matterbridge extends EventEmitter {
2939
2388
  Object.entries(clusterServer.attributes).forEach(([key, value]) => {
2940
2389
  if (clusterServer.name === 'EveHistory')
2941
2390
  return;
2942
- // this.log.debug(`***--clusterServer: ${clusterServer.name}(${clusterServer.id}) attribute:${key}(${value.id}) ${value.isFixed} ${value.isWritable} ${value.isWritable}`);
2943
2391
  let attributeValue;
2944
2392
  try {
2945
2393
  if (typeof value.getLocal() === 'object')
@@ -2950,7 +2398,6 @@ export class Matterbridge extends EventEmitter {
2950
2398
  catch (error) {
2951
2399
  attributeValue = 'Fabric-Scoped';
2952
2400
  this.log.debug(`GetLocal value ${error} in clusterServer: ${clusterServer.name}(${clusterServer.id}) attribute: ${key}(${value.id})`);
2953
- // console.log(error);
2954
2401
  }
2955
2402
  data.push({
2956
2403
  endpoint: device.number ? device.number.toString() : '...',
@@ -2963,14 +2410,12 @@ export class Matterbridge extends EventEmitter {
2963
2410
  });
2964
2411
  });
2965
2412
  device.getChildEndpoints().forEach((childEndpoint) => {
2966
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
2967
2413
  const name = this.edge ? childEndpoint.endpoint?.id : childEndpoint.uniqueStorageKey;
2968
2414
  const clusterServers = childEndpoint.getAllClusterServers();
2969
2415
  clusterServers.forEach((clusterServer) => {
2970
2416
  Object.entries(clusterServer.attributes).forEach(([key, value]) => {
2971
2417
  if (clusterServer.name === 'EveHistory')
2972
2418
  return;
2973
- // this.log.debug(`***--clusterServer: ${clusterServer.name}(${clusterServer.id}) attribute:${key}(${value.id}) ${value.isFixed} ${value.isWritable} ${value.isWritable}`);
2974
2419
  let attributeValue;
2975
2420
  try {
2976
2421
  if (typeof value.getLocal() === 'object')
@@ -2981,7 +2426,6 @@ export class Matterbridge extends EventEmitter {
2981
2426
  catch (error) {
2982
2427
  attributeValue = 'Unavailable';
2983
2428
  this.log.debug(`GetLocal error ${error} in clusterServer: ${clusterServer.name}(${clusterServer.id}) attribute: ${key}(${value.id})`);
2984
- // console.log(error);
2985
2429
  }
2986
2430
  data.push({
2987
2431
  endpoint: (childEndpoint.number ? childEndpoint.number.toString() : '...') + (name ? ' (' + name + ')' : ''),
@@ -2998,7 +2442,6 @@ export class Matterbridge extends EventEmitter {
2998
2442
  });
2999
2443
  res.json(data);
3000
2444
  });
3001
- // Endpoint to view the log
3002
2445
  this.expressApp.get('/api/view-log', async (req, res) => {
3003
2446
  this.log.debug('The frontend sent /api/log');
3004
2447
  try {
@@ -3011,12 +2454,10 @@ export class Matterbridge extends EventEmitter {
3011
2454
  res.status(500).send('Error reading log file');
3012
2455
  }
3013
2456
  });
3014
- // Endpoint to download the matterbridge log
3015
2457
  this.expressApp.get('/api/download-mblog', async (req, res) => {
3016
2458
  this.log.debug('The frontend sent /api/download-mblog');
3017
2459
  try {
3018
2460
  await fs.access(path.join(this.matterbridgeDirectory, this.matterbrideLoggerFile), fs.constants.F_OK);
3019
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
3020
2461
  }
3021
2462
  catch (error) {
3022
2463
  fs.appendFile(path.join(this.matterbridgeDirectory, this.matterbrideLoggerFile), 'Enable the log on file in the settings to enable the file logger');
@@ -3028,12 +2469,10 @@ export class Matterbridge extends EventEmitter {
3028
2469
  }
3029
2470
  });
3030
2471
  });
3031
- // Endpoint to download the matter log
3032
2472
  this.expressApp.get('/api/download-mjlog', async (req, res) => {
3033
2473
  this.log.debug('The frontend sent /api/download-mjlog');
3034
2474
  try {
3035
2475
  await fs.access(path.join(this.matterbridgeDirectory, this.matterLoggerFile), fs.constants.F_OK);
3036
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
3037
2476
  }
3038
2477
  catch (error) {
3039
2478
  fs.appendFile(path.join(this.matterbridgeDirectory, this.matterLoggerFile), 'Enable the log on file in the settings to enable the file logger');
@@ -3045,7 +2484,6 @@ export class Matterbridge extends EventEmitter {
3045
2484
  }
3046
2485
  });
3047
2486
  });
3048
- // Endpoint to download the matter storage file
3049
2487
  this.expressApp.get('/api/download-mjstorage', (req, res) => {
3050
2488
  this.log.debug('The frontend sent /api/download-mjstorage');
3051
2489
  res.download(path.join(this.matterbridgeDirectory, this.matterStorageName), 'matterbridge.json', (error) => {
@@ -3055,7 +2493,6 @@ export class Matterbridge extends EventEmitter {
3055
2493
  }
3056
2494
  });
3057
2495
  });
3058
- // Endpoint to download the matterbridge storage directory
3059
2496
  this.expressApp.get('/api/download-mbstorage', async (req, res) => {
3060
2497
  this.log.debug('The frontend sent /api/download-mbstorage');
3061
2498
  await createZip(path.join(os.tmpdir(), `matterbridge.${this.nodeStorageName}.zip`), path.join(this.matterbridgeDirectory, this.nodeStorageName));
@@ -3066,7 +2503,6 @@ export class Matterbridge extends EventEmitter {
3066
2503
  }
3067
2504
  });
3068
2505
  });
3069
- // Endpoint to download the matterbridge plugin directory
3070
2506
  this.expressApp.get('/api/download-pluginstorage', async (req, res) => {
3071
2507
  this.log.debug('The frontend sent /api/download-pluginstorage');
3072
2508
  await createZip(path.join(os.tmpdir(), `matterbridge.pluginstorage.zip`), this.matterbridgePluginDirectory);
@@ -3077,11 +2513,9 @@ export class Matterbridge extends EventEmitter {
3077
2513
  }
3078
2514
  });
3079
2515
  });
3080
- // Endpoint to download the matterbridge plugin config files
3081
2516
  this.expressApp.get('/api/download-pluginconfig', async (req, res) => {
3082
2517
  this.log.debug('The frontend sent /api/download-pluginconfig');
3083
2518
  await createZip(path.join(os.tmpdir(), `matterbridge.pluginconfig.zip`), path.relative(process.cwd(), path.join(this.matterbridgeDirectory, '*.config.json')));
3084
- // 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')));
3085
2519
  res.download(path.join(os.tmpdir(), `matterbridge.pluginconfig.zip`), `matterbridge.pluginconfig.zip`, (error) => {
3086
2520
  if (error) {
3087
2521
  this.log.error(`Error downloading file matterbridge.pluginstorage.zip: ${error instanceof Error ? error.message : error}`);
@@ -3089,7 +2523,6 @@ export class Matterbridge extends EventEmitter {
3089
2523
  }
3090
2524
  });
3091
2525
  });
3092
- // Endpoint to download the matterbridge plugin config files
3093
2526
  this.expressApp.get('/api/download-backup', async (req, res) => {
3094
2527
  this.log.debug('The frontend sent /api/download-backup');
3095
2528
  res.download(path.join(os.tmpdir(), `matterbridge.backup.zip`), `matterbridge.backup.zip`, (error) => {
@@ -3099,7 +2532,6 @@ export class Matterbridge extends EventEmitter {
3099
2532
  }
3100
2533
  });
3101
2534
  });
3102
- // Endpoint to receive commands
3103
2535
  this.expressApp.post('/api/command/:command/:param', express.json(), async (req, res) => {
3104
2536
  const command = req.params.command;
3105
2537
  let param = req.params.param;
@@ -3109,15 +2541,13 @@ export class Matterbridge extends EventEmitter {
3109
2541
  return;
3110
2542
  }
3111
2543
  this.log.debug(`Received frontend command: ${command}:${param}`);
3112
- // Handle the command setpassword from Settings
3113
2544
  if (command === 'setpassword') {
3114
- const password = param.slice(1, -1); // Remove the first and last characters
2545
+ const password = param.slice(1, -1);
3115
2546
  this.log.debug('setpassword', param, password);
3116
2547
  await this.nodeContext?.set('password', password);
3117
2548
  res.json({ message: 'Command received' });
3118
2549
  return;
3119
2550
  }
3120
- // Handle the command setbridgemode from Settings
3121
2551
  if (command === 'setbridgemode') {
3122
2552
  this.log.debug(`setbridgemode: ${param}`);
3123
2553
  this.wssSendRestartRequired();
@@ -3125,7 +2555,6 @@ export class Matterbridge extends EventEmitter {
3125
2555
  res.json({ message: 'Command received' });
3126
2556
  return;
3127
2557
  }
3128
- // Handle the command backup from Settings
3129
2558
  if (command === 'backup') {
3130
2559
  this.log.notice(`Prepairing the backup...`);
3131
2560
  await createZip(path.join(os.tmpdir(), `matterbridge.backup.zip`), path.join(this.matterbridgeDirectory), path.join(this.matterbridgePluginDirectory));
@@ -3133,26 +2562,25 @@ export class Matterbridge extends EventEmitter {
3133
2562
  res.json({ message: 'Command received' });
3134
2563
  return;
3135
2564
  }
3136
- // Handle the command setmbloglevel from Settings
3137
2565
  if (command === 'setmbloglevel') {
3138
2566
  this.log.debug('Matterbridge log level:', param);
3139
2567
  if (param === 'Debug') {
3140
- this.log.logLevel = "debug" /* LogLevel.DEBUG */;
2568
+ this.log.logLevel = "debug";
3141
2569
  }
3142
2570
  else if (param === 'Info') {
3143
- this.log.logLevel = "info" /* LogLevel.INFO */;
2571
+ this.log.logLevel = "info";
3144
2572
  }
3145
2573
  else if (param === 'Notice') {
3146
- this.log.logLevel = "notice" /* LogLevel.NOTICE */;
2574
+ this.log.logLevel = "notice";
3147
2575
  }
3148
2576
  else if (param === 'Warn') {
3149
- this.log.logLevel = "warn" /* LogLevel.WARN */;
2577
+ this.log.logLevel = "warn";
3150
2578
  }
3151
2579
  else if (param === 'Error') {
3152
- this.log.logLevel = "error" /* LogLevel.ERROR */;
2580
+ this.log.logLevel = "error";
3153
2581
  }
3154
2582
  else if (param === 'Fatal') {
3155
- this.log.logLevel = "fatal" /* LogLevel.FATAL */;
2583
+ this.log.logLevel = "fatal";
3156
2584
  }
3157
2585
  await this.nodeContext?.set('matterbridgeLogLevel', this.log.logLevel);
3158
2586
  MatterbridgeDevice.logLevel = this.log.logLevel;
@@ -3160,13 +2588,12 @@ export class Matterbridge extends EventEmitter {
3160
2588
  for (const plugin of this.plugins) {
3161
2589
  if (!plugin.platform || !plugin.platform.config)
3162
2590
  continue;
3163
- plugin.platform.log.logLevel = plugin.platform.config.debug ? "debug" /* LogLevel.DEBUG */ : this.log.logLevel;
3164
- await plugin.platform.onChangeLoggerLevel(plugin.platform.config.debug ? "debug" /* LogLevel.DEBUG */ : this.log.logLevel);
2591
+ plugin.platform.log.logLevel = plugin.platform.config.debug ? "debug" : this.log.logLevel;
2592
+ await plugin.platform.onChangeLoggerLevel(plugin.platform.config.debug ? "debug" : this.log.logLevel);
3165
2593
  }
3166
2594
  res.json({ message: 'Command received' });
3167
2595
  return;
3168
2596
  }
3169
- // Handle the command setmbloglevel from Settings
3170
2597
  if (command === 'setmjloglevel') {
3171
2598
  this.log.debug('Matter.js log level:', param);
3172
2599
  if (param === 'Debug') {
@@ -3191,34 +2618,30 @@ export class Matterbridge extends EventEmitter {
3191
2618
  res.json({ message: 'Command received' });
3192
2619
  return;
3193
2620
  }
3194
- // Handle the command setmdnsinterface from Settings
3195
2621
  if (command === 'setmdnsinterface') {
3196
- param = param.slice(1, -1); // Remove the first and last characters *mdns*
2622
+ param = param.slice(1, -1);
3197
2623
  this.matterbridgeInformation.mattermdnsinterface = param;
3198
2624
  this.log.debug('Matter.js mdns interface:', param === '' ? 'All interfaces' : param);
3199
2625
  await this.nodeContext?.set('mattermdnsinterface', param);
3200
2626
  res.json({ message: 'Command received' });
3201
2627
  return;
3202
2628
  }
3203
- // Handle the command setipv4address from Settings
3204
2629
  if (command === 'setipv4address') {
3205
- param = param.slice(1, -1); // Remove the first and last characters *ip*
2630
+ param = param.slice(1, -1);
3206
2631
  this.matterbridgeInformation.matteripv4address = param;
3207
2632
  this.log.debug('Matter.js ipv4 address:', param === '' ? 'All ipv4 addresses' : param);
3208
2633
  await this.nodeContext?.set('matteripv4address', param);
3209
2634
  res.json({ message: 'Command received' });
3210
2635
  return;
3211
2636
  }
3212
- // Handle the command setipv6address from Settings
3213
2637
  if (command === 'setipv6address') {
3214
- param = param.slice(1, -1); // Remove the first and last characters *ip*
2638
+ param = param.slice(1, -1);
3215
2639
  this.matterbridgeInformation.matteripv6address = param;
3216
2640
  this.log.debug('Matter.js ipv6 address:', param === '' ? 'All ipv6 addresses' : param);
3217
2641
  await this.nodeContext?.set('matteripv6address', param);
3218
2642
  res.json({ message: 'Command received' });
3219
2643
  return;
3220
2644
  }
3221
- // Handle the command setmatterport from Settings
3222
2645
  if (command === 'setmatterport') {
3223
2646
  const port = Math.min(Math.max(parseInt(param), 5540), 5560);
3224
2647
  this.matterbridgeInformation.matterPort = port;
@@ -3227,7 +2650,6 @@ export class Matterbridge extends EventEmitter {
3227
2650
  res.json({ message: 'Command received' });
3228
2651
  return;
3229
2652
  }
3230
- // Handle the command setmatterdiscriminator from Settings
3231
2653
  if (command === 'setmatterdiscriminator') {
3232
2654
  const discriminator = Math.min(Math.max(parseInt(param), 1000), 4095);
3233
2655
  this.matterbridgeInformation.matterDiscriminator = discriminator;
@@ -3236,7 +2658,6 @@ export class Matterbridge extends EventEmitter {
3236
2658
  res.json({ message: 'Command received' });
3237
2659
  return;
3238
2660
  }
3239
- // Handle the command setmatterpasscode from Settings
3240
2661
  if (command === 'setmatterpasscode') {
3241
2662
  const passcode = Math.min(Math.max(parseInt(param), 10000000), 90000000);
3242
2663
  this.matterbridgeInformation.matterPasscode = passcode;
@@ -3245,20 +2666,17 @@ export class Matterbridge extends EventEmitter {
3245
2666
  res.json({ message: 'Command received' });
3246
2667
  return;
3247
2668
  }
3248
- // Handle the command setmbloglevel from Settings
3249
2669
  if (command === 'setmblogfile') {
3250
2670
  this.log.debug('Matterbridge file log:', param);
3251
2671
  this.matterbridgeInformation.fileLogger = param === 'true';
3252
2672
  await this.nodeContext?.set('matterbridgeFileLog', param === 'true');
3253
- // Create the file logger for matterbridge
3254
2673
  if (param === 'true')
3255
- AnsiLogger.setGlobalLogfile(path.join(this.matterbridgeDirectory, this.matterbrideLoggerFile), "debug" /* LogLevel.DEBUG */, true);
2674
+ AnsiLogger.setGlobalLogfile(path.join(this.matterbridgeDirectory, this.matterbrideLoggerFile), "debug", true);
3256
2675
  else
3257
2676
  AnsiLogger.setGlobalLogfile(undefined);
3258
2677
  res.json({ message: 'Command received' });
3259
2678
  return;
3260
2679
  }
3261
- // Handle the command setmbloglevel from Settings
3262
2680
  if (command === 'setmjlogfile') {
3263
2681
  this.log.debug('Matter file log:', param);
3264
2682
  this.matterbridgeInformation.matterFileLogger = param === 'true';
@@ -3285,43 +2703,36 @@ export class Matterbridge extends EventEmitter {
3285
2703
  res.json({ message: 'Command received' });
3286
2704
  return;
3287
2705
  }
3288
- // Handle the command unregister from Settings
3289
2706
  if (command === 'unregister') {
3290
2707
  await this.unregisterAndShutdownProcess();
3291
2708
  res.json({ message: 'Command received' });
3292
2709
  return;
3293
2710
  }
3294
- // Handle the command reset from Settings
3295
2711
  if (command === 'reset') {
3296
2712
  await this.shutdownProcessAndReset();
3297
2713
  res.json({ message: 'Command received' });
3298
2714
  return;
3299
2715
  }
3300
- // Handle the command factoryreset from Settings
3301
2716
  if (command === 'factoryreset') {
3302
2717
  await this.shutdownProcessAndFactoryReset();
3303
2718
  res.json({ message: 'Command received' });
3304
2719
  return;
3305
2720
  }
3306
- // Handle the command shutdown from Header
3307
2721
  if (command === 'shutdown') {
3308
2722
  await this.shutdownProcess();
3309
2723
  res.json({ message: 'Command received' });
3310
2724
  return;
3311
2725
  }
3312
- // Handle the command restart from Header
3313
2726
  if (command === 'restart') {
3314
2727
  await this.restartProcess();
3315
2728
  res.json({ message: 'Command received' });
3316
2729
  return;
3317
2730
  }
3318
- // Handle the command update from Header
3319
2731
  if (command === 'update') {
3320
2732
  this.log.info('Updating matterbridge...');
3321
2733
  try {
3322
2734
  await this.spawnCommand('npm', ['install', '-g', 'matterbridge', '--omit=dev', '--verbose']);
3323
2735
  this.log.info('Matterbridge has been updated. Full restart required.');
3324
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
3325
2736
  }
3326
2737
  catch (error) {
3327
2738
  this.log.error('Error updating matterbridge');
@@ -3331,11 +2742,9 @@ export class Matterbridge extends EventEmitter {
3331
2742
  res.json({ message: 'Command received' });
3332
2743
  return;
3333
2744
  }
3334
- // Handle the command saveconfig from Home
3335
2745
  if (command === 'saveconfig') {
3336
2746
  param = param.replace(/\*/g, '\\');
3337
2747
  this.log.info(`Saving config for plugin ${plg}${param}${nf}...`);
3338
- // console.log('Req.body:', JSON.stringify(req.body, null, 2));
3339
2748
  if (!this.plugins.has(param)) {
3340
2749
  this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
3341
2750
  }
@@ -3349,39 +2758,33 @@ export class Matterbridge extends EventEmitter {
3349
2758
  res.json({ message: 'Command received' });
3350
2759
  return;
3351
2760
  }
3352
- // Handle the command installplugin from Home
3353
2761
  if (command === 'installplugin') {
3354
2762
  param = param.replace(/\*/g, '\\');
3355
2763
  this.log.info(`Installing plugin ${plg}${param}${nf}...`);
3356
2764
  try {
3357
2765
  await this.spawnCommand('npm', ['install', '-g', param, '--omit=dev', '--verbose']);
3358
2766
  this.log.info(`Plugin ${plg}${param}${nf} installed. Full restart required.`);
3359
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
3360
2767
  }
3361
2768
  catch (error) {
3362
2769
  this.log.error(`Error installing plugin ${plg}${param}${er}`);
3363
2770
  }
3364
2771
  this.wssSendRestartRequired();
3365
2772
  param = param.split('@')[0];
3366
- // Also add the plugin to matterbridge so no return!
3367
2773
  if (param === 'matterbridge') {
3368
- // 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
3369
2774
  res.json({ message: 'Command received' });
3370
2775
  return;
3371
2776
  }
3372
2777
  }
3373
- // Handle the command addplugin from Home
3374
2778
  if (command === 'addplugin' || command === 'installplugin') {
3375
2779
  param = param.replace(/\*/g, '\\');
3376
2780
  const plugin = await this.plugins.add(param);
3377
2781
  if (plugin) {
3378
- this.plugins.load(plugin, true, 'The plugin has been added', true); // No await do it in the background
2782
+ this.plugins.load(plugin, true, 'The plugin has been added', true);
3379
2783
  }
3380
2784
  res.json({ message: 'Command received' });
3381
2785
  this.wssSendRefreshRequired();
3382
2786
  return;
3383
2787
  }
3384
- // Handle the command removeplugin from Home
3385
2788
  if (command === 'removeplugin') {
3386
2789
  if (!this.plugins.has(param)) {
3387
2790
  this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
@@ -3395,7 +2798,6 @@ export class Matterbridge extends EventEmitter {
3395
2798
  this.wssSendRefreshRequired();
3396
2799
  return;
3397
2800
  }
3398
- // Handle the command enableplugin from Home
3399
2801
  if (command === 'enableplugin') {
3400
2802
  if (!this.plugins.has(param)) {
3401
2803
  this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
@@ -3413,14 +2815,13 @@ export class Matterbridge extends EventEmitter {
3413
2815
  plugin.registeredDevices = undefined;
3414
2816
  plugin.addedDevices = undefined;
3415
2817
  await this.plugins.enable(param);
3416
- this.plugins.load(plugin, true, 'The plugin has been enabled', true); // No await do it in the background
2818
+ this.plugins.load(plugin, true, 'The plugin has been enabled', true);
3417
2819
  }
3418
2820
  }
3419
2821
  res.json({ message: 'Command received' });
3420
2822
  this.wssSendRefreshRequired();
3421
2823
  return;
3422
2824
  }
3423
- // Handle the command disableplugin from Home
3424
2825
  if (command === 'disableplugin') {
3425
2826
  if (!this.plugins.has(param)) {
3426
2827
  this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
@@ -3437,7 +2838,6 @@ export class Matterbridge extends EventEmitter {
3437
2838
  return;
3438
2839
  }
3439
2840
  });
3440
- // Fallback for routing (must be the last route)
3441
2841
  this.expressApp.get('*', (req, res) => {
3442
2842
  this.log.debug('The frontend sent:', req.url);
3443
2843
  this.log.debug('Response send file:', path.join(this.rootDirectory, 'frontend/build/index.html'));
@@ -3445,11 +2845,6 @@ export class Matterbridge extends EventEmitter {
3445
2845
  });
3446
2846
  this.log.debug(`Frontend initialized on port ${YELLOW}${port}${db} static ${UNDERLINE}${path.join(this.rootDirectory, 'frontend/build')}${UNDERLINEOFF}${rs}`);
3447
2847
  }
3448
- /**
3449
- * Retrieves the cluster text description from a given device.
3450
- * @param {MatterbridgeDevice} device - The MatterbridgeDevice object.
3451
- * @returns {string} The attributes description of the cluster servers in the device.
3452
- */
3453
2848
  getClusterTextFromDevice(device) {
3454
2849
  const stringifyUserLabel = (endpoint) => {
3455
2850
  const labelList = endpoint.getClusterServer(UserLabelCluster)?.attributes.labelList.getLocal();
@@ -3472,11 +2867,9 @@ export class Matterbridge extends EventEmitter {
3472
2867
  return '';
3473
2868
  };
3474
2869
  let attributes = '';
3475
- // this.log.debug(`***getClusterTextFromDevice: ${device.deviceName} (${device.name})`);
3476
2870
  const clusterServers = device.getAllClusterServers();
3477
2871
  clusterServers.forEach((clusterServer) => {
3478
2872
  try {
3479
- // this.log.debug(`**--clusterServer: ${clusterServer.id} (${clusterServer.name})`);
3480
2873
  if (clusterServer.name === 'OnOff')
3481
2874
  attributes += `OnOff: ${clusterServer.attributes.onOff.getLocal()} `;
3482
2875
  if (clusterServer.name === 'Switch')
@@ -3527,30 +2920,18 @@ export class Matterbridge extends EventEmitter {
3527
2920
  attributes += `${stringifyFixedLabel(device)} `;
3528
2921
  if (clusterServer.name === 'UserLabel')
3529
2922
  attributes += `${stringifyUserLabel(device)} `;
3530
- // this.log.debug(`*--clusterServer: ${clusterServer.id} (${clusterServer.name})`);
3531
2923
  }
3532
2924
  catch (error) {
3533
2925
  this.log.error(`getClusterTextFromDevice with ${clusterServer.name} error: ${error}`);
3534
2926
  }
3535
2927
  });
3536
- // this.log.debug(`*getClusterTextFromDevice: ${device.deviceName} (${device.name})`);
3537
2928
  return attributes;
3538
2929
  }
3539
- /**
3540
- * Initializes the Matterbridge instance as extension for zigbee2mqtt.
3541
- * @deprecated This method is deprecated and will be removed in a future version.
3542
- *
3543
- * @returns A Promise that resolves when the initialization is complete.
3544
- */
3545
2930
  async startExtension(dataPath, extensionVersion, port = 5540) {
3546
- // Set the bridge mode
3547
2931
  this.bridgeMode = 'bridge';
3548
- // Set the first port to use
3549
2932
  this.port = port;
3550
- // Set Matterbridge logger
3551
- this.log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: "info" /* LogLevel.INFO */ });
2933
+ this.log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4, logLevel: "info" });
3552
2934
  this.log.debug('Matterbridge extension is starting...');
3553
- // Initialize NodeStorage
3554
2935
  this.matterbridgeDirectory = dataPath;
3555
2936
  this.log.debug('Creating node storage manager dir: ' + path.join(this.matterbridgeDirectory, 'node_storage'));
3556
2937
  this.nodeStorage = new NodeStorageManager({ dir: path.join(this.matterbridgeDirectory, 'node_storage'), logging: false });
@@ -3569,13 +2950,10 @@ export class Matterbridge extends EventEmitter {
3569
2950
  };
3570
2951
  this.plugins.set(plugin);
3571
2952
  this.plugins.saveToStorage();
3572
- // Log system info and create .matterbridge directory
3573
2953
  await this.logNodeAndSystemInfo();
3574
2954
  this.matterbridgeDirectory = dataPath;
3575
- // Set matter.js logger level and format
3576
2955
  Logger.defaultLogLevel = MatterLogLevel.INFO;
3577
2956
  Logger.format = MatterLogFormat.ANSI;
3578
- // Start the storage and create matterbridgeContext
3579
2957
  await this.startMatterStorage('json', path.join(this.matterbridgeDirectory, this.matterStorageName));
3580
2958
  if (!this.storageManager)
3581
2959
  return false;
@@ -3585,7 +2963,7 @@ export class Matterbridge extends EventEmitter {
3585
2963
  await this.matterbridgeContext.set('softwareVersion', 1);
3586
2964
  await this.matterbridgeContext.set('softwareVersionString', this.matterbridgeVersion);
3587
2965
  await this.matterbridgeContext.set('hardwareVersion', 1);
3588
- await this.matterbridgeContext.set('hardwareVersionString', extensionVersion); // Update with the extension version
2966
+ await this.matterbridgeContext.set('hardwareVersionString', extensionVersion);
3589
2967
  this.matterServer = this.createMatterServer(this.storageManager);
3590
2968
  this.log.debug(`Creating commissioning server for ${plg}Matterbridge${db}`);
3591
2969
  this.commissioningServer = await this.createCommisioningServer(this.matterbridgeContext, 'Matterbridge');
@@ -3598,7 +2976,6 @@ export class Matterbridge extends EventEmitter {
3598
2976
  await this.startMatterServer();
3599
2977
  this.log.info('Matter server started');
3600
2978
  await this.showCommissioningQRCode(this.commissioningServer, this.matterbridgeContext, this.nodeContext, 'Matterbridge');
3601
- // Set reachability to true and trigger event after 60 seconds
3602
2979
  setTimeout(() => {
3603
2980
  this.log.info(`Setting reachability to true for ${plg}Matterbridge${db}`);
3604
2981
  if (this.commissioningServer)
@@ -3608,31 +2985,14 @@ export class Matterbridge extends EventEmitter {
3608
2985
  }, 60 * 1000);
3609
2986
  return this.commissioningServer.isCommissioned();
3610
2987
  }
3611
- /**
3612
- * Close the Matterbridge instance as extension for zigbee2mqtt.
3613
- * @deprecated This method is deprecated and will be removed in a future version.
3614
- *
3615
- * @returns A Promise that resolves when the initialization is complete.
3616
- */
3617
2988
  async stopExtension() {
3618
- // Closing matter
3619
2989
  await this.stopMatterServer();
3620
- // Clearing the session manager
3621
- // this.matterbridgeContext?.createContext('SessionManager').clear();
3622
- // Closing storage
3623
2990
  await this.stopMatterStorage();
3624
2991
  this.log.info('Matter server stopped');
3625
2992
  }
3626
- /**
3627
- * Checks if the extension is commissioned.
3628
- * @deprecated This method is deprecated and will be removed in a future version.
3629
- *
3630
- * @returns {boolean} Returns true if the extension is commissioned, false otherwise.
3631
- */
3632
2993
  isExtensionCommissioned() {
3633
2994
  if (!this.commissioningServer)
3634
2995
  return false;
3635
2996
  return this.commissioningServer.isCommissioned();
3636
2997
  }
3637
2998
  }
3638
- //# sourceMappingURL=matterbridge.js.map