matterbridge 1.6.5 → 1.6.6-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 (95) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/dist/cli.js +0 -26
  3. package/dist/cluster/export.js +0 -2
  4. package/dist/defaultConfigSchema.js +0 -23
  5. package/dist/deviceManager.js +1 -26
  6. package/dist/index.js +0 -30
  7. package/dist/logger/export.js +0 -1
  8. package/dist/matter/export.js +0 -1
  9. package/dist/matterbridge.js +62 -702
  10. package/dist/matterbridgeAccessoryPlatform.js +0 -33
  11. package/dist/matterbridgeBehaviors.js +1 -29
  12. package/dist/matterbridgeDevice.js +39 -933
  13. package/dist/matterbridgeDeviceTypes.js +21 -41
  14. package/dist/matterbridgeDynamicPlatform.js +0 -33
  15. package/dist/matterbridgeEdge.js +0 -525
  16. package/dist/matterbridgeEndpoint.js +61 -1027
  17. package/dist/matterbridgePlatform.js +3 -74
  18. package/dist/matterbridgeTypes.js +0 -24
  19. package/dist/matterbridgeWebsocket.js +0 -45
  20. package/dist/pluginManager.js +3 -237
  21. package/dist/storage/export.js +0 -1
  22. package/dist/utils/colorUtils.js +2 -78
  23. package/dist/utils/export.js +0 -1
  24. package/dist/utils/utils.js +7 -252
  25. package/npm-shrinkwrap.json +12 -15
  26. package/package.json +2 -2
  27. package/dist/cli.d.ts +0 -25
  28. package/dist/cli.d.ts.map +0 -1
  29. package/dist/cli.js.map +0 -1
  30. package/dist/cluster/export.d.ts +0 -2
  31. package/dist/cluster/export.d.ts.map +0 -1
  32. package/dist/cluster/export.js.map +0 -1
  33. package/dist/defaultConfigSchema.d.ts +0 -27
  34. package/dist/defaultConfigSchema.d.ts.map +0 -1
  35. package/dist/defaultConfigSchema.js.map +0 -1
  36. package/dist/deviceManager.d.ts +0 -46
  37. package/dist/deviceManager.d.ts.map +0 -1
  38. package/dist/deviceManager.js.map +0 -1
  39. package/dist/index.d.ts +0 -40
  40. package/dist/index.d.ts.map +0 -1
  41. package/dist/index.js.map +0 -1
  42. package/dist/logger/export.d.ts +0 -2
  43. package/dist/logger/export.d.ts.map +0 -1
  44. package/dist/logger/export.js.map +0 -1
  45. package/dist/matter/export.d.ts +0 -5
  46. package/dist/matter/export.d.ts.map +0 -1
  47. package/dist/matter/export.js.map +0 -1
  48. package/dist/matterbridge.d.ts +0 -466
  49. package/dist/matterbridge.d.ts.map +0 -1
  50. package/dist/matterbridge.js.map +0 -1
  51. package/dist/matterbridgeAccessoryPlatform.d.ts +0 -39
  52. package/dist/matterbridgeAccessoryPlatform.d.ts.map +0 -1
  53. package/dist/matterbridgeAccessoryPlatform.js.map +0 -1
  54. package/dist/matterbridgeBehaviors.d.ts +0 -934
  55. package/dist/matterbridgeBehaviors.d.ts.map +0 -1
  56. package/dist/matterbridgeBehaviors.js.map +0 -1
  57. package/dist/matterbridgeDevice.d.ts +0 -6504
  58. package/dist/matterbridgeDevice.d.ts.map +0 -1
  59. package/dist/matterbridgeDevice.js.map +0 -1
  60. package/dist/matterbridgeDeviceTypes.d.ts +0 -65
  61. package/dist/matterbridgeDeviceTypes.d.ts.map +0 -1
  62. package/dist/matterbridgeDeviceTypes.js.map +0 -1
  63. package/dist/matterbridgeDynamicPlatform.d.ts +0 -39
  64. package/dist/matterbridgeDynamicPlatform.d.ts.map +0 -1
  65. package/dist/matterbridgeDynamicPlatform.js.map +0 -1
  66. package/dist/matterbridgeEdge.d.ts +0 -89
  67. package/dist/matterbridgeEdge.d.ts.map +0 -1
  68. package/dist/matterbridgeEdge.js.map +0 -1
  69. package/dist/matterbridgeEndpoint.d.ts +0 -8529
  70. package/dist/matterbridgeEndpoint.d.ts.map +0 -1
  71. package/dist/matterbridgeEndpoint.js.map +0 -1
  72. package/dist/matterbridgePlatform.d.ts +0 -96
  73. package/dist/matterbridgePlatform.d.ts.map +0 -1
  74. package/dist/matterbridgePlatform.js.map +0 -1
  75. package/dist/matterbridgeTypes.d.ts +0 -147
  76. package/dist/matterbridgeTypes.d.ts.map +0 -1
  77. package/dist/matterbridgeTypes.js.map +0 -1
  78. package/dist/matterbridgeWebsocket.d.ts +0 -49
  79. package/dist/matterbridgeWebsocket.d.ts.map +0 -1
  80. package/dist/matterbridgeWebsocket.js.map +0 -1
  81. package/dist/pluginManager.d.ts +0 -238
  82. package/dist/pluginManager.d.ts.map +0 -1
  83. package/dist/pluginManager.js.map +0 -1
  84. package/dist/storage/export.d.ts +0 -2
  85. package/dist/storage/export.d.ts.map +0 -1
  86. package/dist/storage/export.js.map +0 -1
  87. package/dist/utils/colorUtils.d.ts +0 -61
  88. package/dist/utils/colorUtils.d.ts.map +0 -1
  89. package/dist/utils/colorUtils.js.map +0 -1
  90. package/dist/utils/export.d.ts +0 -3
  91. package/dist/utils/export.d.ts.map +0 -1
  92. package/dist/utils/export.js.map +0 -1
  93. package/dist/utils/utils.d.ts +0 -221
  94. package/dist/utils/utils.d.ts.map +0 -1
  95. package/dist/utils/utils.js.map +0 -1
@@ -1,26 +1,3 @@
1
- /**
2
- * This file contains the class Matterbridge.
3
- *
4
- * @file matterbridge.ts
5
- * @author Luca Liguori
6
- * @date 2023-12-29
7
- * @version 1.5.2
8
- *
9
- * Copyright 2023, 2024, 2025 Luca Liguori.
10
- *
11
- * Licensed under the Apache License, Version 2.0 (the "License");
12
- * you may not use this file except in compliance with the License.
13
- * You may obtain a copy of the License at
14
- *
15
- * http://www.apache.org/licenses/LICENSE-2.0
16
- *
17
- * Unless required by applicable law or agreed to in writing, software
18
- * distributed under the License is distributed on an "AS IS" BASIS,
19
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20
- * See the License for the specific language governing permissions and
21
- * limitations under the License. *
22
- */
23
- // Node.js modules
24
1
  import { fileURLToPath } from 'url';
25
2
  import { promises as fs } from 'fs';
26
3
  import { exec, spawn } from 'child_process';
@@ -29,35 +6,26 @@ import EventEmitter from 'events';
29
6
  import os from 'os';
30
7
  import path from 'path';
31
8
  import { randomBytes } from 'crypto';
32
- // Package modules
33
9
  import https from 'https';
34
10
  import express from 'express';
35
11
  import WebSocket, { WebSocketServer } from 'ws';
36
- // NodeStorage and AnsiLogger modules
37
12
  import { NodeStorageManager } from 'node-persist-manager';
38
13
  import { AnsiLogger, UNDERLINE, UNDERLINEOFF, YELLOW, db, debugStringify, stringify, BRIGHT, RESET, er, nf, rs, wr, RED, GREEN, zb, CYAN, nt, idn, or, hk, BLUE } from 'node-ansi-logger';
39
- // Matterbridge
40
14
  import { MatterbridgeDevice } from './matterbridgeDevice.js';
41
15
  import { WS_ID_LOG, WS_ID_REFRESH_NEEDED, WS_ID_RESTART_NEEDED, wsMessageHandler } from './matterbridgeWebsocket.js';
42
16
  import { logInterfaces, wait, waiter, createZip, copyDirectory, getParameter, getIntParameter, hasParameter } from './utils/utils.js';
43
17
  import { PluginManager } from './pluginManager.js';
44
18
  import { DeviceManager } from './deviceManager.js';
45
19
  import { MatterbridgeEndpoint } from './matterbridgeEndpoint.js';
46
- // @matter
47
20
  import { DeviceTypeId, Logger, LogLevel as MatterLogLevel, LogFormat as MatterLogFormat, VendorId, StorageManager, EndpointServer } from '@matter/main';
48
21
  import { BasicInformationCluster, BridgedDeviceBasicInformation, BridgedDeviceBasicInformationCluster, FixedLabelCluster, GeneralCommissioning, PowerSourceCluster, SwitchCluster, ThreadNetworkDiagnosticsCluster, UserLabelCluster, } from '@matter/main/clusters';
49
22
  import { getClusterNameById, ManualPairingCodeCodec, QrCodeSchema } from '@matter/main/types';
50
23
  import { StorageBackendDisk, StorageBackendJsonFile } from '@matter/nodejs';
51
- // @project-chip
52
24
  import { CommissioningController, CommissioningServer, MatterServer } from '@project-chip/matter.js';
53
25
  import { Aggregator, DeviceTypes, NodeStateInformation } from '@project-chip/matter.js/device';
54
- // Default colors
55
26
  const plg = '\u001B[38;5;33m';
56
27
  const dev = '\u001B[38;5;79m';
57
28
  const typ = '\u001B[38;5;207m';
58
- /**
59
- * Represents the Matterbridge application.
60
- */
61
29
  export class Matterbridge extends EventEmitter {
62
30
  systemInformation = {
63
31
  interfaceName: '',
@@ -93,7 +61,7 @@ export class Matterbridge extends EventEmitter {
93
61
  restartMode: '',
94
62
  edge: hasParameter('edge'),
95
63
  profile: getParameter('profile'),
96
- loggerLevel: "info" /* LogLevel.INFO */,
64
+ loggerLevel: "info",
97
65
  fileLogger: false,
98
66
  matterLoggerLevel: MatterLogLevel.INFO,
99
67
  matterFileLogger: false,
@@ -129,7 +97,6 @@ export class Matterbridge extends EventEmitter {
129
97
  nodeContext;
130
98
  matterStorageName = 'matterbridge' + (getParameter('profile') ? '.' + getParameter('profile') : '') + '.json';
131
99
  nodeStorageName = 'storage' + (getParameter('profile') ? '.' + getParameter('profile') : '');
132
- // Cleanup
133
100
  hasCleanupStarted = false;
134
101
  initialized = false;
135
102
  execRunningCount = 0;
@@ -141,18 +108,16 @@ export class Matterbridge extends EventEmitter {
141
108
  sigtermHandler;
142
109
  exceptionHandler;
143
110
  rejectionHandler;
144
- // Frontend
145
111
  expressApp;
146
112
  httpServer;
147
113
  httpsServer;
148
114
  webSocketServer;
149
- // Matter
150
- mdnsInterface; // matter server mdnsInterface: e.g. 'eth0' or 'wlan0' or 'WiFi'
151
- ipv4address; // matter commissioning server listeningAddressIpv4
152
- ipv6address; // matter commissioning server listeningAddressIpv6
153
- port = 5540; // first commissioning server port
154
- passcode; // first commissioning server passcode
155
- discriminator; // first commissioning server discriminator
115
+ mdnsInterface;
116
+ ipv4address;
117
+ ipv6address;
118
+ port = 5540;
119
+ passcode;
120
+ discriminator;
156
121
  storageManager;
157
122
  matterbridgeContext;
158
123
  mattercontrollerContext;
@@ -163,26 +128,13 @@ export class Matterbridge extends EventEmitter {
163
128
  aggregatorVendorId = VendorId(getIntParameter('vendorId') ?? 0xfff1);
164
129
  aggregatorProductId = getIntParameter('productId') ?? 0x8000;
165
130
  static instance;
166
- // We load asyncronously so is private
167
131
  constructor() {
168
132
  super();
169
- // Bind the handler to the instance
170
133
  this.matterbridgeMessageHandler = wsMessageHandler.bind(this);
171
134
  }
172
135
  matterbridgeMessageHandler;
173
- /** ***********************************************************************************************************************************/
174
- /** loadInstance() and cleanup() methods */
175
- /** ***********************************************************************************************************************************/
176
- /**
177
- * Loads an instance of the Matterbridge class.
178
- * If an instance already exists, return that instance.
179
- *
180
- * @param initialize - Whether to initialize the Matterbridge instance after loading.
181
- * @returns The loaded Matterbridge instance.
182
- */
183
136
  static async loadInstance(initialize = false) {
184
137
  if (!Matterbridge.instance) {
185
- // eslint-disable-next-line no-console
186
138
  if (hasParameter('debug'))
187
139
  console.log(GREEN + 'Creating a new instance of Matterbridge.', initialize ? 'Initializing...' : 'Not initializing...', rs);
188
140
  Matterbridge.instance = new Matterbridge();
@@ -191,11 +143,6 @@ export class Matterbridge extends EventEmitter {
191
143
  }
192
144
  return Matterbridge.instance;
193
145
  }
194
- /**
195
- * Call cleanup().
196
- * @deprecated This method is deprecated and is only used for jest tests.
197
- *
198
- */
199
146
  async destroyInstance() {
200
147
  await this.cleanup('destroying instance...', false);
201
148
  await waiter('destroying instance...', () => {
@@ -203,66 +150,42 @@ export class Matterbridge extends EventEmitter {
203
150
  }, false, 60000, 100, false);
204
151
  await wait(1000, 'Wait for the global node_modules and matterbridge version', false);
205
152
  }
206
- /**
207
- * Initializes the Matterbridge application.
208
- *
209
- * @remarks
210
- * This method performs the necessary setup and initialization steps for the Matterbridge application.
211
- * It displays the help information if the 'help' parameter is provided, sets up the logger, checks the
212
- * node version, registers signal handlers, initializes storage, and parses the command line.
213
- *
214
- * @returns A Promise that resolves when the initialization is complete.
215
- */
216
153
  async initialize() {
217
- // Set the first port to use for the commissioning server (will be incremented in childbridge mode)
218
154
  this.port = getIntParameter('port') ?? 5540;
219
- // Set the first passcode to use for the commissioning server (will be incremented in childbridge mode)
220
155
  this.passcode = getIntParameter('passcode');
221
- // Set the first discriminator to use for the commissioning server (will be incremented in childbridge mode)
222
156
  this.discriminator = getIntParameter('discriminator');
223
- // Set the restart mode
224
157
  if (hasParameter('service'))
225
158
  this.restartMode = 'service';
226
159
  if (hasParameter('docker'))
227
160
  this.restartMode = 'docker';
228
- // Set the matterbridge directory
229
161
  this.homeDirectory = getParameter('homedir') ?? os.homedir();
230
162
  this.matterbridgeDirectory = path.join(this.homeDirectory, '.matterbridge');
231
- // Create matterbridge logger
232
- this.log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: hasParameter('debug') ? "debug" /* LogLevel.DEBUG */ : "info" /* LogLevel.INFO */ });
233
- // Initialize nodeStorage and nodeContext
163
+ this.log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4, logLevel: hasParameter('debug') ? "debug" : "info" });
234
164
  try {
235
165
  this.log.debug(`Creating node storage manager: ${CYAN}${this.nodeStorageName}${db}`);
236
166
  this.nodeStorage = new NodeStorageManager({ dir: path.join(this.matterbridgeDirectory, this.nodeStorageName), writeQueue: false, expiredInterval: undefined, logging: false });
237
167
  this.log.debug('Creating node storage context for matterbridge');
238
168
  this.nodeContext = await this.nodeStorage.createStorage('matterbridge');
239
- // TODO: Remove this code when node-persist-manager is updated
240
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
241
169
  const keys = (await this.nodeStorage?.storage.keys());
242
170
  for (const key of keys) {
243
171
  this.log.debug(`Checking node storage manager key: ${CYAN}${key}${db}`);
244
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
245
172
  await this.nodeStorage?.storage.get(key);
246
173
  }
247
174
  const storages = await this.nodeStorage.getStorageNames();
248
175
  for (const storage of storages) {
249
176
  this.log.debug(`Checking storage: ${CYAN}${storage}${db}`);
250
177
  const nodeContext = await this.nodeStorage?.createStorage(storage);
251
- // TODO: Remove this code when node-persist-manager is updated
252
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
253
178
  const keys = (await nodeContext?.storage.keys());
254
179
  keys.forEach(async (key) => {
255
180
  this.log.debug(`Checking key: ${CYAN}${storage}:${key}${db}`);
256
181
  await nodeContext?.get(key);
257
182
  });
258
183
  }
259
- // Creating a backup of the node storage since it is not corrupted
260
184
  this.log.debug('Creating node storage backup...');
261
185
  await copyDirectory(path.join(this.matterbridgeDirectory, this.nodeStorageName), path.join(this.matterbridgeDirectory, this.nodeStorageName + '.backup'));
262
186
  this.log.debug('Created node storage backup');
263
187
  }
264
188
  catch (error) {
265
- // Restoring the backup of the node storage since it is corrupted
266
189
  this.log.error(`Error creating node storage manager and context: ${error instanceof Error ? error.message : error}`);
267
190
  if (hasParameter('norestore')) {
268
191
  this.log.fatal(`The matterbridge node storage is corrupted. Parameter -norestore found: exiting...`);
@@ -277,44 +200,41 @@ export class Matterbridge extends EventEmitter {
277
200
  this.log.fatal('Fatal error creating node storage manager and context for matterbridge');
278
201
  throw new Error('Fatal error creating node storage manager and context for matterbridge');
279
202
  }
280
- // Set matterbridge logger level (context: matterbridgeLogLevel)
281
203
  if (hasParameter('logger')) {
282
204
  const level = getParameter('logger');
283
205
  if (level === 'debug') {
284
- this.log.logLevel = "debug" /* LogLevel.DEBUG */;
206
+ this.log.logLevel = "debug";
285
207
  }
286
208
  else if (level === 'info') {
287
- this.log.logLevel = "info" /* LogLevel.INFO */;
209
+ this.log.logLevel = "info";
288
210
  }
289
211
  else if (level === 'notice') {
290
- this.log.logLevel = "notice" /* LogLevel.NOTICE */;
212
+ this.log.logLevel = "notice";
291
213
  }
292
214
  else if (level === 'warn') {
293
- this.log.logLevel = "warn" /* LogLevel.WARN */;
215
+ this.log.logLevel = "warn";
294
216
  }
295
217
  else if (level === 'error') {
296
- this.log.logLevel = "error" /* LogLevel.ERROR */;
218
+ this.log.logLevel = "error";
297
219
  }
298
220
  else if (level === 'fatal') {
299
- this.log.logLevel = "fatal" /* LogLevel.FATAL */;
221
+ this.log.logLevel = "fatal";
300
222
  }
301
223
  else {
302
224
  this.log.warn(`Invalid matterbridge logger level: ${level}. Using default level "info".`);
303
- this.log.logLevel = "info" /* LogLevel.INFO */;
225
+ this.log.logLevel = "info";
304
226
  }
305
227
  }
306
228
  else {
307
- this.log.logLevel = await this.nodeContext.get('matterbridgeLogLevel', "info" /* LogLevel.INFO */);
229
+ this.log.logLevel = await this.nodeContext.get('matterbridgeLogLevel', "info");
308
230
  }
309
231
  MatterbridgeDevice.logLevel = this.log.logLevel;
310
- // Create the file logger for matterbridge (context: matterbridgeFileLog)
311
232
  if (hasParameter('filelogger') || (await this.nodeContext.get('matterbridgeFileLog', false))) {
312
233
  AnsiLogger.setGlobalLogfile(path.join(this.matterbridgeDirectory, this.matterbrideLoggerFile), this.log.logLevel, true);
313
234
  this.matterbridgeInformation.fileLogger = true;
314
235
  }
315
236
  this.log.notice('Matterbridge is starting...');
316
237
  this.log.debug(`Matterbridge logLevel: ${this.log.logLevel} fileLoger: ${this.matterbridgeInformation.fileLogger}.`);
317
- // Set matter.js logger level, format and logger (context: matterLogLevel)
318
238
  if (hasParameter('matterlogger')) {
319
239
  const level = getParameter('matterlogger');
320
240
  if (level === 'debug') {
@@ -345,7 +265,6 @@ export class Matterbridge extends EventEmitter {
345
265
  }
346
266
  Logger.format = MatterLogFormat.ANSI;
347
267
  Logger.setLogger('default', this.createMatterLogger());
348
- // Create the file logger for matter.js (context: matterFileLog)
349
268
  if (hasParameter('matterfilelogger') || (await this.nodeContext.get('matterFileLog', false))) {
350
269
  this.matterbridgeInformation.matterFileLogger = true;
351
270
  Logger.addLogger('matterfilelogger', await this.createMatterFileLogger(path.join(this.matterbridgeDirectory, this.matterLoggerFile), true), {
@@ -354,7 +273,6 @@ export class Matterbridge extends EventEmitter {
354
273
  });
355
274
  }
356
275
  this.log.debug(`Matter logLevel: ${Logger.defaultLogLevel} fileLoger: ${this.matterbridgeInformation.matterFileLogger}.`);
357
- // Set the interface to use for the matter server mdnsInterface
358
276
  if (hasParameter('mdnsinterface')) {
359
277
  this.mdnsInterface = getParameter('mdnsinterface');
360
278
  }
@@ -363,7 +281,6 @@ export class Matterbridge extends EventEmitter {
363
281
  if (this.mdnsInterface === '')
364
282
  this.mdnsInterface = undefined;
365
283
  }
366
- // Set the listeningAddressIpv4 for the matter commissioning server
367
284
  if (hasParameter('ipv4address')) {
368
285
  this.ipv4address = getParameter('ipv4address');
369
286
  }
@@ -372,7 +289,6 @@ export class Matterbridge extends EventEmitter {
372
289
  if (this.ipv4address === '')
373
290
  this.ipv4address = undefined;
374
291
  }
375
- // Set the listeningAddressIpv6 for the matter commissioning server
376
292
  if (hasParameter('ipv6address')) {
377
293
  this.ipv6address = getParameter('ipv6address');
378
294
  }
@@ -381,23 +297,17 @@ export class Matterbridge extends EventEmitter {
381
297
  if (this.ipv6address === '')
382
298
  this.ipv6address = undefined;
383
299
  }
384
- // Initialize PluginManager
385
300
  this.plugins = new PluginManager(this);
386
301
  await this.plugins.loadFromStorage();
387
- // Initialize DeviceManager
388
302
  this.devices = new DeviceManager(this, this.nodeContext);
389
- // Get the plugins from node storage and create the plugins node storage contexts
390
303
  for (const plugin of this.plugins) {
391
304
  const packageJson = await this.plugins.parse(plugin);
392
305
  if (packageJson === null && !hasParameter('add')) {
393
- // Try to reinstall the plugin from npm (for Docker pull and external plugins)
394
- // We don't do this when the add parameter is set because we shut down the process after adding the plugin
395
306
  this.log.info(`Error parsing plugin ${plg}${plugin.name}${nf}. Trying to reinstall it from npm.`);
396
307
  try {
397
308
  await this.spawnCommand('npm', ['install', '-g', plugin.name, '--omit=dev', '--verbose']);
398
309
  this.log.info(`Plugin ${plg}${plugin.name}${nf} reinstalled.`);
399
310
  plugin.error = false;
400
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
401
311
  }
402
312
  catch (error) {
403
313
  plugin.error = true;
@@ -414,7 +324,6 @@ export class Matterbridge extends EventEmitter {
414
324
  await plugin.nodeContext.set('description', plugin.description);
415
325
  await plugin.nodeContext.set('author', plugin.author);
416
326
  }
417
- // Log system info and create .matterbridge directory
418
327
  await this.logNodeAndSystemInfo();
419
328
  this.log.notice(`Matterbridge version ${this.matterbridgeVersion} ` +
420
329
  `${hasParameter('bridge') || (!hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'bridge') ? 'mode bridge ' : ''}` +
@@ -422,7 +331,6 @@ export class Matterbridge extends EventEmitter {
422
331
  `${hasParameter('controller') ? 'mode controller ' : ''}` +
423
332
  `${this.restartMode !== '' ? 'restart mode ' + this.restartMode + ' ' : ''}` +
424
333
  `running on ${this.systemInformation.osType} (v.${this.systemInformation.osRelease}) platform ${this.systemInformation.osPlatform} arch ${this.systemInformation.osArch}`);
425
- // Check node version and throw error
426
334
  const minNodeVersion = 18;
427
335
  const nodeVersion = process.versions.node;
428
336
  const versionMajor = parseInt(nodeVersion.split('.')[0]);
@@ -430,17 +338,10 @@ export class Matterbridge extends EventEmitter {
430
338
  this.log.error(`Node version ${versionMajor} is not supported. Please upgrade to ${minNodeVersion} or above.`);
431
339
  throw new Error(`Node version ${versionMajor} is not supported. Please upgrade to ${minNodeVersion} or above.`);
432
340
  }
433
- // Register process handlers
434
341
  this.registerProcessHandlers();
435
- // Parse command line
436
342
  await this.parseCommandLine();
437
343
  this.initialized = true;
438
344
  }
439
- /**
440
- * Parses the command line arguments and performs the corresponding actions.
441
- * @private
442
- * @returns {Promise<void>} A promise that resolves when the command line arguments have been processed, or the process exits.
443
- */
444
345
  async parseCommandLine() {
445
346
  if (hasParameter('help')) {
446
347
  this.log.info(`\nUsage: matterbridge [options]\n
@@ -548,14 +449,12 @@ export class Matterbridge extends EventEmitter {
548
449
  }
549
450
  if (hasParameter('factoryreset')) {
550
451
  try {
551
- // Delete matter storage file
552
452
  await fs.unlink(path.join(this.matterbridgeDirectory, this.matterStorageName));
553
453
  }
554
454
  catch (err) {
555
455
  this.log.error(`Error deleting storage: ${err}`);
556
456
  }
557
457
  try {
558
- // Delete node storage directory with its subdirectories
559
458
  await fs.rm(path.join(this.matterbridgeDirectory, this.nodeStorageName), { recursive: true });
560
459
  }
561
460
  catch (err) {
@@ -569,7 +468,6 @@ export class Matterbridge extends EventEmitter {
569
468
  this.emit('shutdown');
570
469
  return;
571
470
  }
572
- // Start the matter storage and create the matterbridge context
573
471
  try {
574
472
  await this.startMatterStorage('json', path.join(this.matterbridgeDirectory, this.matterStorageName));
575
473
  }
@@ -604,34 +502,28 @@ export class Matterbridge extends EventEmitter {
604
502
  this.emit('shutdown');
605
503
  return;
606
504
  }
607
- // Initialize frontend
608
505
  if (getIntParameter('frontend') !== 0 || getIntParameter('frontend') === undefined)
609
506
  await this.initializeFrontend(getIntParameter('frontend'));
610
- // Check each 60 minutes the latest versions
611
507
  this.checkUpdateInterval = setInterval(() => {
612
508
  this.getMatterbridgeLatestVersion();
613
509
  for (const plugin of this.plugins) {
614
510
  this.getPluginLatestVersion(plugin);
615
511
  }
616
512
  }, 60 * 60 * 1000);
617
- // Start the matterbridge in mode test
618
513
  if (hasParameter('test')) {
619
514
  this.bridgeMode = 'bridge';
620
515
  MatterbridgeDevice.bridgeMode = 'bridge';
621
516
  return;
622
517
  }
623
- // Start the matterbridge in mode controller
624
518
  if (hasParameter('controller')) {
625
519
  this.bridgeMode = 'controller';
626
520
  await this.startController();
627
521
  return;
628
522
  }
629
- // Check if the bridge mode is set and start matterbridge in bridge mode if not set
630
523
  if (!hasParameter('bridge') && !hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === '') {
631
524
  this.log.info('Setting default matterbridge start mode to bridge');
632
525
  await this.nodeContext?.set('bridgeMode', 'bridge');
633
526
  }
634
- // Start matterbridge in bridge mode
635
527
  if (hasParameter('bridge') || (!hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'bridge')) {
636
528
  this.bridgeMode = 'bridge';
637
529
  MatterbridgeDevice.bridgeMode = 'bridge';
@@ -640,7 +532,6 @@ export class Matterbridge extends EventEmitter {
640
532
  await this.startBridge();
641
533
  return;
642
534
  }
643
- // Start matterbridge in childbridge mode
644
535
  if (hasParameter('childbridge') || (!hasParameter('bridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'childbridge')) {
645
536
  this.bridgeMode = 'childbridge';
646
537
  MatterbridgeDevice.bridgeMode = 'childbridge';
@@ -650,28 +541,17 @@ export class Matterbridge extends EventEmitter {
650
541
  return;
651
542
  }
652
543
  }
653
- /**
654
- * Asynchronously loads and starts the registered plugins.
655
- *
656
- * This method is responsible for initializing and staarting all enabled plugins.
657
- * It ensures that each plugin is properly loaded and started before the ridge starts.
658
- *
659
- * @returns {Promise<void>} A promise that resolves when all plugins have been loaded and started.
660
- */
661
544
  async startPlugins() {
662
- // Check, load and start the plugins
663
545
  for (const plugin of this.plugins) {
664
546
  plugin.configJson = await this.plugins.loadConfig(plugin);
665
547
  plugin.schemaJson = await this.plugins.loadSchema(plugin);
666
- // Check if the plugin is available
667
548
  if (!(await this.plugins.resolve(plugin.path))) {
668
549
  this.log.error(`Plugin ${plg}${plugin.name}${er} not found or not validated. Disabling it.`);
669
550
  plugin.enabled = false;
670
551
  plugin.error = true;
671
552
  continue;
672
553
  }
673
- // Check if the plugin has a new version
674
- this.getPluginLatestVersion(plugin); // No await do it asyncronously
554
+ this.getPluginLatestVersion(plugin);
675
555
  if (!plugin.enabled) {
676
556
  this.log.info(`Plugin ${plg}${plugin.name}${nf} not enabled`);
677
557
  continue;
@@ -686,26 +566,20 @@ export class Matterbridge extends EventEmitter {
686
566
  plugin.addedDevices = undefined;
687
567
  plugin.qrPairingCode = undefined;
688
568
  plugin.manualPairingCode = undefined;
689
- this.plugins.load(plugin, true, 'Matterbridge is starting'); // No await do it asyncronously
569
+ this.plugins.load(plugin, true, 'Matterbridge is starting');
690
570
  }
691
571
  this.wssSendRefreshRequired();
692
572
  }
693
- /**
694
- * Registers the process handlers for uncaughtException, unhandledRejection, SIGINT and SIGTERM.
695
- * When either of these signals are received, the cleanup method is called with an appropriate message.
696
- */
697
573
  registerProcessHandlers() {
698
574
  this.log.debug(`Registering uncaughtException and unhandledRejection handlers...`);
699
575
  process.removeAllListeners('uncaughtException');
700
576
  process.removeAllListeners('unhandledRejection');
701
577
  this.exceptionHandler = async (error) => {
702
578
  this.log.fatal('Unhandled Exception detected at:', error.stack || error, rs);
703
- // await this.cleanup('Unhandled Exception detected, cleaning up...');
704
579
  };
705
580
  process.on('uncaughtException', this.exceptionHandler);
706
581
  this.rejectionHandler = async (reason, promise) => {
707
582
  this.log.fatal('Unhandled Rejection detected at:', promise, 'reason:', reason instanceof Error ? reason.stack : reason, rs);
708
- // await this.cleanup('Unhandled Rejection detected, cleaning up...');
709
583
  };
710
584
  process.on('unhandledRejection', this.rejectionHandler);
711
585
  this.log.debug(`Registering SIGINT and SIGTERM signal handlers...`);
@@ -718,9 +592,6 @@ export class Matterbridge extends EventEmitter {
718
592
  };
719
593
  process.on('SIGTERM', this.sigtermHandler);
720
594
  }
721
- /**
722
- * Deregisters the process uncaughtException, unhandledRejection, SIGINT and SIGTERM signal handlers.
723
- */
724
595
  deregisterProcesslHandlers() {
725
596
  this.log.debug(`Deregistering uncaughtException and unhandledRejection handlers...`);
726
597
  if (this.exceptionHandler)
@@ -737,11 +608,7 @@ export class Matterbridge extends EventEmitter {
737
608
  process.off('SIGTERM', this.sigtermHandler);
738
609
  this.sigtermHandler = undefined;
739
610
  }
740
- /**
741
- * Logs the node and system information.
742
- */
743
611
  async logNodeAndSystemInfo() {
744
- // IP address information
745
612
  const networkInterfaces = os.networkInterfaces();
746
613
  this.systemInformation.ipv4Address = '';
747
614
  this.systemInformation.ipv6Address = '';
@@ -761,7 +628,7 @@ export class Matterbridge extends EventEmitter {
761
628
  this.systemInformation.macAddress = detail.mac;
762
629
  }
763
630
  }
764
- if (this.systemInformation.ipv4Address !== '' /* && this.systemInformation.ipv6Address !== ''*/) {
631
+ if (this.systemInformation.ipv4Address !== '') {
765
632
  this.log.debug(`Using interface: '${this.systemInformation.interfaceName}'`);
766
633
  this.log.debug(`- with MAC address: '${this.systemInformation.macAddress}'`);
767
634
  this.log.debug(`- with IPv4 address: '${this.systemInformation.ipv4Address}'`);
@@ -769,22 +636,19 @@ export class Matterbridge extends EventEmitter {
769
636
  break;
770
637
  }
771
638
  }
772
- // Node information
773
639
  this.systemInformation.nodeVersion = process.versions.node;
774
640
  const versionMajor = parseInt(this.systemInformation.nodeVersion.split('.')[0]);
775
641
  const versionMinor = parseInt(this.systemInformation.nodeVersion.split('.')[1]);
776
642
  const versionPatch = parseInt(this.systemInformation.nodeVersion.split('.')[2]);
777
- // Host system information
778
643
  this.systemInformation.hostname = os.hostname();
779
644
  this.systemInformation.user = os.userInfo().username;
780
- this.systemInformation.osType = os.type(); // "Windows_NT", "Darwin", etc.
781
- this.systemInformation.osRelease = os.release(); // Kernel version
782
- this.systemInformation.osPlatform = os.platform(); // "win32", "linux", "darwin", etc.
783
- this.systemInformation.osArch = os.arch(); // "x64", "arm", etc.
784
- this.systemInformation.totalMemory = (os.totalmem() / 1024 / 1024 / 1024).toFixed(2) + ' GB'; // Convert to GB
785
- this.systemInformation.freeMemory = (os.freemem() / 1024 / 1024 / 1024).toFixed(2) + ' GB'; // Convert to GB
786
- this.systemInformation.systemUptime = (os.uptime() / 60 / 60).toFixed(2) + ' hours'; // Convert to hours
787
- // Log the system information
645
+ this.systemInformation.osType = os.type();
646
+ this.systemInformation.osRelease = os.release();
647
+ this.systemInformation.osPlatform = os.platform();
648
+ this.systemInformation.osArch = os.arch();
649
+ this.systemInformation.totalMemory = (os.totalmem() / 1024 / 1024 / 1024).toFixed(2) + ' GB';
650
+ this.systemInformation.freeMemory = (os.freemem() / 1024 / 1024 / 1024).toFixed(2) + ' GB';
651
+ this.systemInformation.systemUptime = (os.uptime() / 60 / 60).toFixed(2) + ' hours';
788
652
  this.log.debug('Host System Information:');
789
653
  this.log.debug(`- Hostname: ${this.systemInformation.hostname}`);
790
654
  this.log.debug(`- User: ${this.systemInformation.user}`);
@@ -800,19 +664,15 @@ export class Matterbridge extends EventEmitter {
800
664
  this.log.debug(`- Total Memory: ${this.systemInformation.totalMemory}`);
801
665
  this.log.debug(`- Free Memory: ${this.systemInformation.freeMemory}`);
802
666
  this.log.debug(`- System Uptime: ${this.systemInformation.systemUptime}`);
803
- // Home directory
804
667
  this.homeDirectory = getParameter('homedir') ?? os.homedir();
805
668
  this.matterbridgeInformation.homeDirectory = this.homeDirectory;
806
669
  this.log.debug(`Home Directory: ${this.homeDirectory}`);
807
- // Package root directory
808
670
  const currentFileDirectory = path.dirname(fileURLToPath(import.meta.url));
809
671
  this.rootDirectory = path.resolve(currentFileDirectory, '../');
810
672
  this.matterbridgeInformation.rootDirectory = this.rootDirectory;
811
673
  this.log.debug(`Root Directory: ${this.rootDirectory}`);
812
- // Global node_modules directory
813
674
  if (this.nodeContext)
814
675
  this.globalModulesDirectory = await this.nodeContext.get('globalModulesDirectory', '');
815
- // First run of Matterbridge so the node storage is empty
816
676
  if (this.globalModulesDirectory === '') {
817
677
  try {
818
678
  this.globalModulesDirectory = await this.getGlobalNodeModules();
@@ -836,7 +696,6 @@ export class Matterbridge extends EventEmitter {
836
696
  this.log.error(`Error getting global node_modules directory: ${error}`);
837
697
  });
838
698
  }
839
- // Create the data directory .matterbridge in the home directory
840
699
  this.matterbridgeDirectory = path.join(this.homeDirectory, '.matterbridge');
841
700
  this.matterbridgeInformation.matterbridgeDirectory = this.matterbridgeDirectory;
842
701
  try {
@@ -860,7 +719,6 @@ export class Matterbridge extends EventEmitter {
860
719
  }
861
720
  }
862
721
  this.log.debug(`Matterbridge Directory: ${this.matterbridgeDirectory}`);
863
- // Create the plugin directory Matterbridge in the home directory
864
722
  this.matterbridgePluginDirectory = path.join(this.homeDirectory, 'Matterbridge');
865
723
  this.matterbridgeInformation.matterbridgePluginDirectory = this.matterbridgePluginDirectory;
866
724
  try {
@@ -884,28 +742,19 @@ export class Matterbridge extends EventEmitter {
884
742
  }
885
743
  }
886
744
  this.log.debug(`Matterbridge Plugin Directory: ${this.matterbridgePluginDirectory}`);
887
- // Matterbridge version
888
745
  const packageJson = JSON.parse(await fs.readFile(path.join(this.rootDirectory, 'package.json'), 'utf-8'));
889
746
  this.matterbridgeVersion = packageJson.version;
890
747
  this.matterbridgeInformation.matterbridgeVersion = this.matterbridgeVersion;
891
748
  this.log.debug(`Matterbridge Version: ${this.matterbridgeVersion}`);
892
- // Matterbridge latest version
893
749
  if (this.nodeContext)
894
750
  this.matterbridgeLatestVersion = await this.nodeContext.get('matterbridgeLatestVersion', '');
895
751
  this.log.debug(`Matterbridge Latest Version: ${this.matterbridgeLatestVersion}`);
896
752
  this.getMatterbridgeLatestVersion();
897
- // Current working directory
898
753
  const currentDir = process.cwd();
899
754
  this.log.debug(`Current Working Directory: ${currentDir}`);
900
- // Command line arguments (excluding 'node' and the script name)
901
755
  const cmdArgs = process.argv.slice(2).join(' ');
902
756
  this.log.debug(`Command Line Arguments: ${cmdArgs}`);
903
757
  }
904
- /**
905
- * Retrieves the latest version of a package from the npm registry.
906
- * @param packageName - The name of the package.
907
- * @returns A Promise that resolves to the latest version of the package.
908
- */
909
758
  async getLatestVersion(packageName) {
910
759
  return new Promise((resolve, reject) => {
911
760
  this.execRunningCount++;
@@ -920,10 +769,6 @@ export class Matterbridge extends EventEmitter {
920
769
  });
921
770
  });
922
771
  }
923
- /**
924
- * Retrieves the path to the global Node.js modules directory.
925
- * @returns A promise that resolves to the path of the global Node.js modules directory.
926
- */
927
772
  async getGlobalNodeModules() {
928
773
  return new Promise((resolve, reject) => {
929
774
  this.execRunningCount++;
@@ -938,11 +783,6 @@ export class Matterbridge extends EventEmitter {
938
783
  });
939
784
  });
940
785
  }
941
- /**
942
- * Retrieves the latest version of Matterbridge and performs necessary actions based on the version comparison.
943
- * @private
944
- * @returns {Promise<void>} A promise that resolves when the latest version is retrieved and actions are performed.
945
- */
946
786
  async getMatterbridgeLatestVersion() {
947
787
  this.getLatestVersion('matterbridge')
948
788
  .then(async (matterbridgeLatestVersion) => {
@@ -959,19 +799,8 @@ export class Matterbridge extends EventEmitter {
959
799
  })
960
800
  .catch((error) => {
961
801
  this.log.error(`Error getting Matterbridge latest version: ${error.message}`);
962
- // error.stack && this.log.debug(error.stack);
963
802
  });
964
803
  }
965
- /**
966
- * Retrieves the latest version of a plugin and updates the plugin's latestVersion property.
967
- * If the plugin's version is different from the latest version, logs a warning message.
968
- * If the plugin's version is the same as the latest version, logs an info message.
969
- * If there is an error retrieving the latest version, logs an error message.
970
- *
971
- * @private
972
- * @param {RegisteredPlugin} plugin - The plugin for which to retrieve the latest version.
973
- * @returns {Promise<void>} A promise that resolves when the latest version is retrieved and actions are performed.
974
- */
975
804
  async getPluginLatestVersion(plugin) {
976
805
  this.getLatestVersion(plugin.name)
977
806
  .then(async (latestVersion) => {
@@ -983,54 +812,40 @@ export class Matterbridge extends EventEmitter {
983
812
  })
984
813
  .catch((error) => {
985
814
  this.log.error(`Error getting ${plg}${plugin.name}${er} latest version: ${error.message}`);
986
- // error.stack && this.log.debug(error.stack);
987
815
  });
988
816
  }
989
- /**
990
- * Creates a MatterLogger function to show the matter.js log messages in AnsiLogger (for the frontend).
991
- *
992
- * @returns {Function} The MatterLogger function.
993
- */
994
817
  createMatterLogger() {
995
- const matterLogger = new AnsiLogger({ logName: 'Matter', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: "debug" /* LogLevel.DEBUG */ });
818
+ const matterLogger = new AnsiLogger({ logName: 'Matter', logTimestampFormat: 4, logLevel: "debug" });
996
819
  return (_level, formattedLog) => {
997
820
  const logger = formattedLog.slice(44, 44 + 20).trim();
998
821
  const message = formattedLog.slice(65);
999
822
  matterLogger.logName = logger;
1000
823
  switch (_level) {
1001
824
  case MatterLogLevel.DEBUG:
1002
- matterLogger.log("debug" /* LogLevel.DEBUG */, message);
825
+ matterLogger.log("debug", message);
1003
826
  break;
1004
827
  case MatterLogLevel.INFO:
1005
- matterLogger.log("info" /* LogLevel.INFO */, message);
828
+ matterLogger.log("info", message);
1006
829
  break;
1007
830
  case MatterLogLevel.NOTICE:
1008
- matterLogger.log("notice" /* LogLevel.NOTICE */, message);
831
+ matterLogger.log("notice", message);
1009
832
  break;
1010
833
  case MatterLogLevel.WARN:
1011
- matterLogger.log("warn" /* LogLevel.WARN */, message);
834
+ matterLogger.log("warn", message);
1012
835
  break;
1013
836
  case MatterLogLevel.ERROR:
1014
- matterLogger.log("error" /* LogLevel.ERROR */, message);
837
+ matterLogger.log("error", message);
1015
838
  break;
1016
839
  case MatterLogLevel.FATAL:
1017
- matterLogger.log("fatal" /* LogLevel.FATAL */, message);
840
+ matterLogger.log("fatal", message);
1018
841
  break;
1019
842
  default:
1020
- matterLogger.log("debug" /* LogLevel.DEBUG */, message);
843
+ matterLogger.log("debug", message);
1021
844
  break;
1022
845
  }
1023
846
  };
1024
847
  }
1025
- /**
1026
- * Creates a Matter File Logger.
1027
- *
1028
- * @param {string} filePath - The path to the log file.
1029
- * @param {boolean} [unlink=false] - Whether to unlink the log file before creating a new one.
1030
- * @returns {Function} - A function that logs formatted messages to the log file.
1031
- */
1032
848
  async createMatterFileLogger(filePath, unlink = false) {
1033
- // 2024-08-21 08:55:19.488 DEBUG InteractionMessenger Sending DataReport chunk with 28 attributes and 0 events: 1004 bytes
1034
849
  let fileSize = 0;
1035
850
  if (unlink) {
1036
851
  try {
@@ -1079,83 +894,53 @@ export class Matterbridge extends EventEmitter {
1079
894
  }
1080
895
  };
1081
896
  }
1082
- /**
1083
- * Update matterbridge and cleanup.
1084
- */
1085
897
  async updateProcess() {
1086
898
  await this.cleanup('updating...', false);
1087
899
  }
1088
- /**
1089
- * Restarts the process by spawning a new process and exiting the current process.
1090
- */
1091
900
  async restartProcess() {
1092
901
  await this.cleanup('restarting...', true);
1093
902
  }
1094
- /**
1095
- * Shut down the process by exiting the current process.
1096
- */
1097
903
  async shutdownProcess() {
1098
904
  await this.cleanup('shutting down...', false);
1099
905
  }
1100
- /**
1101
- * Shut down the process and reset.
1102
- */
1103
906
  async unregisterAndShutdownProcess() {
1104
907
  this.log.info('Unregistering all devices and shutting down...');
1105
- for (const plugin of this.plugins /* .filter((plugin) => plugin.enabled && !plugin.error))*/) {
908
+ for (const plugin of this.plugins) {
1106
909
  await this.removeAllBridgedDevices(plugin.name);
1107
910
  }
1108
911
  await this.cleanup('unregistered all devices and shutting down...', false);
1109
912
  }
1110
- /**
1111
- * Shut down the process and reset.
1112
- */
1113
913
  async shutdownProcessAndReset() {
1114
914
  await this.cleanup('shutting down with reset...', false);
1115
915
  }
1116
- /**
1117
- * Shut down the process and factory reset.
1118
- */
1119
916
  async shutdownProcessAndFactoryReset() {
1120
917
  await this.cleanup('shutting down with factory reset...', false);
1121
918
  }
1122
- /**
1123
- * Cleans up the Matterbridge instance.
1124
- * @param message - The cleanup message.
1125
- * @param restart - Indicates whether to restart the instance after cleanup. Default is `false`.
1126
- * @returns A promise that resolves when the cleanup is completed.
1127
- */
1128
919
  async cleanup(message, restart = false) {
1129
920
  if (this.initialized && !this.hasCleanupStarted) {
1130
921
  this.hasCleanupStarted = true;
1131
922
  this.log.info(message);
1132
- // Deregisters the process handlers
1133
923
  this.deregisterProcesslHandlers();
1134
- // Clear the start matter interval
1135
924
  if (this.startMatterInterval) {
1136
925
  clearInterval(this.startMatterInterval);
1137
926
  this.startMatterInterval = undefined;
1138
927
  this.log.debug('Start matter interval cleared');
1139
928
  }
1140
- // Clear the check update interval
1141
929
  if (this.checkUpdateInterval) {
1142
930
  clearInterval(this.checkUpdateInterval);
1143
931
  this.checkUpdateInterval = undefined;
1144
932
  this.log.debug('Check update interval cleared');
1145
933
  }
1146
- // Clear the configure timeout
1147
934
  if (this.configureTimeout) {
1148
935
  clearTimeout(this.configureTimeout);
1149
936
  this.configureTimeout = undefined;
1150
937
  this.log.debug('Matterbridge configure timeout cleared');
1151
938
  }
1152
- // Clear the reachability timeout
1153
939
  if (this.reachabilityTimeout) {
1154
940
  clearTimeout(this.reachabilityTimeout);
1155
941
  this.reachabilityTimeout = undefined;
1156
942
  this.log.debug('Matterbridge reachability timeout cleared');
1157
943
  }
1158
- // Calling the shutdown method of each plugin and clear the reachability timeout
1159
944
  for (const plugin of this.plugins) {
1160
945
  if (!plugin.enabled || plugin.error)
1161
946
  continue;
@@ -1166,29 +951,24 @@ export class Matterbridge extends EventEmitter {
1166
951
  this.log.debug(`Plugin ${plg}${plugin.name}${db} reachability timeout cleared`);
1167
952
  }
1168
953
  }
1169
- // Close the http server
1170
954
  if (this.httpServer) {
1171
955
  this.httpServer.close();
1172
956
  this.httpServer.removeAllListeners();
1173
957
  this.httpServer = undefined;
1174
958
  this.log.debug('Frontend http server closed successfully');
1175
959
  }
1176
- // Close the https server
1177
960
  if (this.httpsServer) {
1178
961
  this.httpsServer.close();
1179
962
  this.httpsServer.removeAllListeners();
1180
963
  this.httpsServer = undefined;
1181
964
  this.log.debug('Frontend https server closed successfully');
1182
965
  }
1183
- // Remove listeners from the express app
1184
966
  if (this.expressApp) {
1185
967
  this.expressApp.removeAllListeners();
1186
968
  this.expressApp = undefined;
1187
969
  this.log.debug('Frontend app closed successfully');
1188
970
  }
1189
- // Close the WebSocket server
1190
971
  if (this.webSocketServer) {
1191
- // Close all active connections
1192
972
  this.webSocketServer.clients.forEach((client) => {
1193
973
  if (client.readyState === WebSocket.OPEN) {
1194
974
  client.close();
@@ -1204,35 +984,26 @@ export class Matterbridge extends EventEmitter {
1204
984
  });
1205
985
  this.webSocketServer = undefined;
1206
986
  }
1207
- // Closing matter
1208
987
  await this.stopMatterServer();
1209
- // Closing matter storage
1210
988
  await this.stopMatterStorage();
1211
- // Remove the matterfilelogger
1212
989
  try {
1213
990
  Logger.removeLogger('matterfilelogger');
1214
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1215
991
  }
1216
992
  catch (error) {
1217
- // this.log.debug(`Error removing the matterfilelogger for file ${CYAN}${path.join(this.matterbridgeDirectory, this.matterLoggerFile)}${er}: ${error instanceof Error ? error.message : error}`);
1218
993
  }
1219
- // Serialize registeredDevices
1220
994
  if (this.nodeStorage && this.nodeContext) {
1221
995
  this.log.info('Saving registered devices...');
1222
996
  const serializedRegisteredDevices = [];
1223
997
  this.devices.forEach(async (device) => {
1224
998
  const serializedMatterbridgeDevice = device.serialize();
1225
- // this.log.info(`- ${serializedMatterbridgeDevice.deviceName}${rs}\n`, serializedMatterbridgeDevice);
1226
999
  if (serializedMatterbridgeDevice)
1227
1000
  serializedRegisteredDevices.push(serializedMatterbridgeDevice);
1228
1001
  });
1229
1002
  await this.nodeContext.set('devices', serializedRegisteredDevices);
1230
1003
  this.log.info(`Saved registered devices (${serializedRegisteredDevices?.length})`);
1231
- // Clear nodeContext and nodeStorage (they just need 1000ms to write the data to disk)
1232
1004
  this.log.debug(`Closing node storage context for ${plg}Matterbridge${db}...`);
1233
1005
  await this.nodeContext.close();
1234
1006
  this.nodeContext = undefined;
1235
- // Clear nodeContext for each plugin (they just need 1000ms to write the data to disk)
1236
1007
  for (const plugin of this.plugins) {
1237
1008
  if (plugin.nodeContext) {
1238
1009
  this.log.debug(`Closing node storage context for plugin ${plg}${plugin.name}${db}...`);
@@ -1263,16 +1034,13 @@ export class Matterbridge extends EventEmitter {
1263
1034
  }
1264
1035
  else {
1265
1036
  if (message === 'shutting down with reset...') {
1266
- // Delete matter storage file
1267
1037
  this.log.info('Resetting Matterbridge commissioning information...');
1268
1038
  await fs.unlink(path.join(this.matterbridgeDirectory, this.matterStorageName));
1269
1039
  this.log.info('Reset done! Remove all paired devices from the controllers.');
1270
1040
  }
1271
1041
  if (message === 'shutting down with factory reset...') {
1272
- // Delete matter storage file
1273
1042
  this.log.info('Resetting Matterbridge commissioning information...');
1274
1043
  await fs.unlink(path.join(this.matterbridgeDirectory, this.matterStorageName));
1275
- // Delete node storage directory with its subdirectories
1276
1044
  this.log.info('Resetting Matterbridge storage...');
1277
1045
  await fs.rm(path.join(this.matterbridgeDirectory, this.nodeStorageName), { recursive: true });
1278
1046
  this.log.info('Factory reset done! Remove all paired devices from the controllers.');
@@ -1285,33 +1053,19 @@ export class Matterbridge extends EventEmitter {
1285
1053
  this.initialized = false;
1286
1054
  }
1287
1055
  }
1288
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1289
1056
  async addBridgedEndpoint(pluginName, device) {
1290
- // Nothing to do here
1291
1057
  }
1292
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1293
1058
  async removeBridgedEndpoint(pluginName, device) {
1294
- // Nothing to do here
1295
1059
  }
1296
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1297
1060
  async removeAllBridgedEndpoints(pluginName) {
1298
- // Nothing to do here
1299
1061
  }
1300
- /**
1301
- * Adds a bridged device to the Matterbridge.
1302
- * @param pluginName - The name of the plugin.
1303
- * @param device - The bridged device to add.
1304
- * @returns {Promise<void>} - A promise that resolves when the device is added.
1305
- */
1306
1062
  async addBridgedDevice(pluginName, device) {
1307
1063
  this.log.debug(`Adding bridged device ${dev}${device.deviceName}${db} (${zb}${device.name}${db}) for plugin ${plg}${pluginName}${db}`);
1308
- // Check if the plugin is registered
1309
1064
  const plugin = this.plugins.get(pluginName);
1310
1065
  if (!plugin) {
1311
1066
  this.log.error(`Error adding bridged device ${dev}${device.deviceName}${er} (${zb}${device.name}${er}) plugin ${plg}${pluginName}${er} not found`);
1312
1067
  return;
1313
1068
  }
1314
- // Register and add the device to matterbridge aggregator in bridge mode
1315
1069
  if (this.bridgeMode === 'bridge') {
1316
1070
  if (!this.matterAggregator) {
1317
1071
  this.log.error(`Adding bridged device ${dev}${device.deviceName}${er} (${zb}${device.name}${er}) for plugin ${plg}${pluginName}${er} error: matterAggregator not found`);
@@ -1319,11 +1073,8 @@ export class Matterbridge extends EventEmitter {
1319
1073
  }
1320
1074
  this.matterAggregator.addBridgedDevice(device);
1321
1075
  }
1322
- // The first time create the commissioning server and the aggregator for DynamicPlatform
1323
- // Register and add the device in childbridge mode
1324
1076
  if (this.bridgeMode === 'childbridge') {
1325
1077
  if (plugin.type === 'AccessoryPlatform') {
1326
- // Check if the plugin is locked with the commissioning server
1327
1078
  if (!plugin.locked) {
1328
1079
  plugin.locked = true;
1329
1080
  plugin.storageContext = await this.importCommissioningServerContext(plugin.name, device);
@@ -1337,7 +1088,6 @@ export class Matterbridge extends EventEmitter {
1337
1088
  }
1338
1089
  }
1339
1090
  if (plugin.type === 'DynamicPlatform') {
1340
- // Check if the plugin is locked with the commissioning server and the aggregator
1341
1091
  if (!plugin.locked) {
1342
1092
  plugin.locked = true;
1343
1093
  this.log.debug(`Creating commissioning server context for ${plg}${plugin.name}${db}`);
@@ -1345,7 +1095,7 @@ export class Matterbridge extends EventEmitter {
1345
1095
  this.log.debug(`Creating commissioning server for ${plg}${plugin.name}${db}`);
1346
1096
  plugin.commissioningServer = await this.createCommisioningServer(plugin.storageContext, plugin.name);
1347
1097
  this.log.debug(`Creating aggregator for plugin ${plg}${plugin.name}${db}`);
1348
- plugin.aggregator = await this.createMatterAggregator(plugin.storageContext, plugin.name); // Generate serialNumber and uniqueId
1098
+ plugin.aggregator = await this.createMatterAggregator(plugin.storageContext, plugin.name);
1349
1099
  this.log.debug(`Adding matter aggregator to commissioning server for plugin ${plg}${plugin.name}${db}`);
1350
1100
  plugin.commissioningServer.addDevice(plugin.aggregator);
1351
1101
  this.log.debug(`Adding commissioning server to matter server for plugin ${plg}${plugin.name}${db}`);
@@ -1358,25 +1108,16 @@ export class Matterbridge extends EventEmitter {
1358
1108
  plugin.registeredDevices++;
1359
1109
  if (plugin.addedDevices !== undefined)
1360
1110
  plugin.addedDevices++;
1361
- // Add the device to the DeviceManager
1362
1111
  this.devices.set(device);
1363
1112
  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}`);
1364
1113
  }
1365
- /**
1366
- * Removes a bridged device from the Matterbridge.
1367
- * @param pluginName - The name of the plugin.
1368
- * @param device - The device to be removed.
1369
- * @returns A Promise that resolves when the device is successfully removed.
1370
- */
1371
1114
  async removeBridgedDevice(pluginName, device) {
1372
1115
  this.log.debug(`Removing bridged device ${dev}${device.deviceName}${db} (${zb}${device.name}${db}) for plugin ${plg}${pluginName}${db}`);
1373
- // Check if the plugin is registered
1374
1116
  const plugin = this.plugins.get(pluginName);
1375
1117
  if (!plugin) {
1376
1118
  this.log.error(`Error removing bridged device ${dev}${device.deviceName}${er} (${zb}${device.name}${er}) for plugin ${plg}${pluginName}${er}: plugin not found`);
1377
1119
  return;
1378
1120
  }
1379
- // Remove the device from matterbridge aggregator in bridge mode
1380
1121
  if (this.bridgeMode === 'bridge') {
1381
1122
  if (!this.matterAggregator) {
1382
1123
  this.log.error(`Error removing bridged device ${dev}${device.deviceName}${er} (${zb}${device.name}${er}) for plugin ${plg}${pluginName}${er}: matterAggregator not found`);
@@ -1386,8 +1127,6 @@ export class Matterbridge extends EventEmitter {
1386
1127
  device.setBridgedDeviceReachability(false);
1387
1128
  device.getClusterServerById(BridgedDeviceBasicInformation.Cluster.id)?.triggerReachableChangedEvent({ reachableNewValue: false });
1388
1129
  }
1389
- // device.getClusterServerById(BridgedDeviceBasicInformation.Cluster.id)?.triggerShutDownEvent({});
1390
- // device.getClusterServerById(BridgedDeviceBasicInformation.Cluster.id)?.triggerLeaveEvent({});
1391
1130
  this.matterAggregator?.removeBridgedDevice(device);
1392
1131
  this.log.info(`Removed bridged device(${plugin.registeredDevices}/${plugin.addedDevices}) ${dev}${device.deviceName}${nf} (${zb}${device.name}${nf}) for plugin ${plg}${pluginName}${nf}`);
1393
1132
  if (plugin.registeredDevices !== undefined)
@@ -1395,7 +1134,6 @@ export class Matterbridge extends EventEmitter {
1395
1134
  if (plugin.addedDevices !== undefined)
1396
1135
  plugin.addedDevices--;
1397
1136
  }
1398
- // Remove the device in childbridge mode
1399
1137
  if (this.bridgeMode === 'childbridge') {
1400
1138
  if (plugin.type === 'AccessoryPlatform') {
1401
1139
  if (!plugin.commissioningServer) {
@@ -1419,22 +1157,14 @@ export class Matterbridge extends EventEmitter {
1419
1157
  plugin.registeredDevices--;
1420
1158
  if (plugin.addedDevices !== undefined)
1421
1159
  plugin.addedDevices--;
1422
- // Remove the commissioning server
1423
1160
  if (plugin.registeredDevices === 0 && plugin.addedDevices === 0 && plugin.commissioningServer) {
1424
1161
  this.matterServer?.removeCommissioningServer(plugin.commissioningServer);
1425
1162
  plugin.commissioningServer = undefined;
1426
1163
  this.log.info(`Removed commissioning server for plugin ${plg}${pluginName}${nf}`);
1427
1164
  }
1428
1165
  }
1429
- // Remove the device from the DeviceManager
1430
1166
  this.devices.remove(device);
1431
1167
  }
1432
- /**
1433
- * Removes all bridged devices associated with a specific plugin.
1434
- *
1435
- * @param pluginName - The name of the plugin.
1436
- * @returns A promise that resolves when all devices have been removed.
1437
- */
1438
1168
  async removeAllBridgedDevices(pluginName) {
1439
1169
  this.log.debug(`Removing all bridged devices for plugin ${plg}${pluginName}${db}`);
1440
1170
  this.devices.forEach(async (device) => {
@@ -1443,13 +1173,7 @@ export class Matterbridge extends EventEmitter {
1443
1173
  }
1444
1174
  });
1445
1175
  }
1446
- /**
1447
- * Starts the Matterbridge in bridge mode.
1448
- * @private
1449
- * @returns {Promise<void>} A promise that resolves when the Matterbridge is started.
1450
- */
1451
1176
  async startBridge() {
1452
- // Plugins are configured by a timer when matter server is started and plugin.configured is set to true
1453
1177
  if (!this.storageManager)
1454
1178
  throw new Error('No storage manager initialized');
1455
1179
  if (!this.matterbridgeContext)
@@ -1468,7 +1192,6 @@ export class Matterbridge extends EventEmitter {
1468
1192
  let failCount = 0;
1469
1193
  this.startMatterInterval = setInterval(async () => {
1470
1194
  for (const plugin of this.plugins) {
1471
- // new code to not start the bridge if one plugin is in error cause the controllers will delete the devices loosing all the configuration
1472
1195
  if (!plugin.enabled)
1473
1196
  continue;
1474
1197
  if (plugin.error) {
@@ -1493,18 +1216,15 @@ export class Matterbridge extends EventEmitter {
1493
1216
  clearInterval(this.startMatterInterval);
1494
1217
  this.startMatterInterval = undefined;
1495
1218
  this.log.debug('Cleared startMatterInterval interval for Matterbridge');
1496
- // Start the Matter server
1497
1219
  await this.startMatterServer();
1498
1220
  this.log.notice('Matter server started');
1499
- // Show the QR code for commissioning or log the already commissioned message
1500
1221
  await this.showCommissioningQRCode(this.commissioningServer, this.matterbridgeContext, this.nodeContext, 'Matterbridge');
1501
- // Configure the plugins
1502
1222
  this.configureTimeout = setTimeout(async () => {
1503
1223
  for (const plugin of this.plugins) {
1504
1224
  if (!plugin.enabled || !plugin.loaded || !plugin.started || plugin.error)
1505
1225
  continue;
1506
1226
  try {
1507
- await this.plugins.configure(plugin); // TODO No await do it in parallel
1227
+ await this.plugins.configure(plugin);
1508
1228
  }
1509
1229
  catch (error) {
1510
1230
  plugin.error = true;
@@ -1513,7 +1233,6 @@ export class Matterbridge extends EventEmitter {
1513
1233
  }
1514
1234
  this.wssSendRefreshRequired();
1515
1235
  }, 30 * 1000);
1516
- // Setting reachability to true
1517
1236
  this.reachabilityTimeout = setTimeout(() => {
1518
1237
  this.log.info(`Setting reachability to true for ${plg}Matterbridge${db}`);
1519
1238
  if (this.commissioningServer)
@@ -1523,14 +1242,7 @@ export class Matterbridge extends EventEmitter {
1523
1242
  }, 60 * 1000);
1524
1243
  }, 1000);
1525
1244
  }
1526
- /**
1527
- * Starts the Matterbridge in childbridge mode.
1528
- * @private
1529
- * @returns {Promise<void>} A promise that resolves when the Matterbridge is started.
1530
- */
1531
1245
  async startChildbridge() {
1532
- // Matterbridge.addBridgedDevice creates the commissionig servers and add the devices to the the commissioning server or to the aggregator
1533
- // Plugins are configured by a timer when matter server is started and plugin.configured is set to true
1534
1246
  if (!this.storageManager)
1535
1247
  throw new Error('No storage manager initialized');
1536
1248
  this.matterServer = this.createMatterServer(this.storageManager);
@@ -1540,7 +1252,6 @@ export class Matterbridge extends EventEmitter {
1540
1252
  this.startMatterInterval = setInterval(async () => {
1541
1253
  let allStarted = true;
1542
1254
  for (const plugin of this.plugins) {
1543
- // new code to not start the bridge if one plugin is in error cause the controllers will delete the devices loosing all the configuration
1544
1255
  if (!plugin.enabled)
1545
1256
  continue;
1546
1257
  if (plugin.error) {
@@ -1568,16 +1279,14 @@ export class Matterbridge extends EventEmitter {
1568
1279
  clearInterval(this.startMatterInterval);
1569
1280
  this.startMatterInterval = undefined;
1570
1281
  this.log.debug('Cleared startMatterInterval interval in childbridge mode');
1571
- // Start the Matter server
1572
1282
  await this.startMatterServer();
1573
1283
  this.log.notice('Matter server started');
1574
- // Configure the plugins
1575
1284
  this.configureTimeout = setTimeout(async () => {
1576
1285
  for (const plugin of this.plugins) {
1577
1286
  if (!plugin.enabled || !plugin.loaded || !plugin.started || plugin.error)
1578
1287
  continue;
1579
1288
  try {
1580
- await this.plugins.configure(plugin); // TODO No await do it in parallel
1289
+ await this.plugins.configure(plugin);
1581
1290
  }
1582
1291
  catch (error) {
1583
1292
  plugin.error = true;
@@ -1606,7 +1315,6 @@ export class Matterbridge extends EventEmitter {
1606
1315
  continue;
1607
1316
  }
1608
1317
  await this.showCommissioningQRCode(plugin.commissioningServer, plugin.storageContext, plugin.nodeContext, plugin.name);
1609
- // Setting reachability to true
1610
1318
  plugin.reachabilityTimeout = setTimeout(() => {
1611
1319
  this.log.info(`Setting reachability to true for ${plg}${plugin.name}${db}`);
1612
1320
  if (plugin.commissioningServer)
@@ -1619,11 +1327,6 @@ export class Matterbridge extends EventEmitter {
1619
1327
  }
1620
1328
  }, 1000);
1621
1329
  }
1622
- /**
1623
- * Starts the Matterbridge controller.
1624
- * @private
1625
- * @returns {Promise<void>} A promise that resolves when the Matterbridge is started.
1626
- */
1627
1330
  async startController() {
1628
1331
  if (!this.storageManager) {
1629
1332
  this.log.error('No storage manager initialized');
@@ -1686,7 +1389,7 @@ export class Matterbridge extends EventEmitter {
1686
1389
  const nodeId = await this.commissioningController.commissionNode(options);
1687
1390
  this.log.info(`Commissioning successfully done with nodeId: ${nodeId}`);
1688
1391
  this.log.info('ActiveSessionInformation:', this.commissioningController.getActiveSessionInformation());
1689
- } // (hasParameter('pairingcode'))
1392
+ }
1690
1393
  if (hasParameter('unpairall')) {
1691
1394
  this.log.info('***Commissioning controller unpairing all nodes...');
1692
1395
  const nodeIds = this.commissioningController.getCommissionedNodes();
@@ -1697,8 +1400,6 @@ export class Matterbridge extends EventEmitter {
1697
1400
  return;
1698
1401
  }
1699
1402
  if (hasParameter('discover')) {
1700
- // const discover = await this.commissioningController.discoverCommissionableDevices({ productId: 0x8000, deviceType: 0xfff1 });
1701
- // console.log(discover);
1702
1403
  }
1703
1404
  if (!this.commissioningController.isCommissioned()) {
1704
1405
  this.log.info('***Commissioning controller is not commissioned: use matterbridge -controller -pairingcode [pairingcode] to commission a device');
@@ -1739,12 +1440,10 @@ export class Matterbridge extends EventEmitter {
1739
1440
  },
1740
1441
  });
1741
1442
  node.logStructure();
1742
- // Get the interaction client
1743
1443
  this.log.info('Getting the interaction client');
1744
1444
  const interactionClient = await node.getInteractionClient();
1745
1445
  let cluster;
1746
1446
  let attributes;
1747
- // Log BasicInformationCluster
1748
1447
  cluster = BasicInformationCluster;
1749
1448
  attributes = await interactionClient.getMultipleAttributes({
1750
1449
  attributes: [{ clusterId: cluster.id }],
@@ -1754,7 +1453,6 @@ export class Matterbridge extends EventEmitter {
1754
1453
  attributes.forEach((attribute) => {
1755
1454
  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}`);
1756
1455
  });
1757
- // Log PowerSourceCluster
1758
1456
  cluster = PowerSourceCluster;
1759
1457
  attributes = await interactionClient.getMultipleAttributes({
1760
1458
  attributes: [{ clusterId: cluster.id }],
@@ -1764,7 +1462,6 @@ export class Matterbridge extends EventEmitter {
1764
1462
  attributes.forEach((attribute) => {
1765
1463
  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}`);
1766
1464
  });
1767
- // Log ThreadNetworkDiagnostics
1768
1465
  cluster = ThreadNetworkDiagnosticsCluster;
1769
1466
  attributes = await interactionClient.getMultipleAttributes({
1770
1467
  attributes: [{ clusterId: cluster.id }],
@@ -1774,7 +1471,6 @@ export class Matterbridge extends EventEmitter {
1774
1471
  attributes.forEach((attribute) => {
1775
1472
  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}`);
1776
1473
  });
1777
- // Log SwitchCluster
1778
1474
  cluster = SwitchCluster;
1779
1475
  attributes = await interactionClient.getMultipleAttributes({
1780
1476
  attributes: [{ clusterId: cluster.id }],
@@ -1795,15 +1491,6 @@ export class Matterbridge extends EventEmitter {
1795
1491
  this.log.info('Subscribed to all attributes and events');
1796
1492
  }
1797
1493
  }
1798
- /** ***********************************************************************************************************************************/
1799
- /** Matter.js methods */
1800
- /** ***********************************************************************************************************************************/
1801
- /**
1802
- * Starts the matter storage process based on the specified storage type and name.
1803
- * @param {string} storageType - The type of storage to start (e.g., 'disk', 'json').
1804
- * @param {string} storageName - The name of the storage file.
1805
- * @returns {Promise<void>} - A promise that resolves when the storage process is started.
1806
- */
1807
1494
  async startMatterStorage(storageType, storageName) {
1808
1495
  this.log.debug(`Starting matter ${storageType} storage ${CYAN}${storageName}${db}`);
1809
1496
  if (storageType === 'disk') {
@@ -1849,12 +1536,6 @@ export class Matterbridge extends EventEmitter {
1849
1536
  this.log.debug(`Creating commissioning server context for ${plg}Matterbridge${db}`);
1850
1537
  this.matterbridgeContext = await this.createCommissioningServerContext('Matterbridge', 'Matterbridge', DeviceTypes.AGGREGATOR.code, 0xfff1, 'Matterbridge', 0x8000, 'Matterbridge aggregator');
1851
1538
  }
1852
- /**
1853
- * Makes a backup copy of the specified matter JSON storage file.
1854
- *
1855
- * @param storageName - The name of the JSON storage file to be backed up.
1856
- * @param backupName - The name of the backup file to be created.
1857
- */
1858
1539
  async backupMatterStorage(storageName, backupName) {
1859
1540
  try {
1860
1541
  this.log.debug(`Making backup copy of ${storageName}`);
@@ -1875,12 +1556,6 @@ export class Matterbridge extends EventEmitter {
1875
1556
  }
1876
1557
  }
1877
1558
  }
1878
- /**
1879
- * Restore the specified matter JSON storage file.
1880
- *
1881
- * @param backupName - The name of the backup file to restore from.
1882
- * @param storageName - The name of the JSON storage file to restored.
1883
- */
1884
1559
  async restoreMatterStorage(backupName, storageName) {
1885
1560
  try {
1886
1561
  this.log.notice(`Restoring the backup copy of ${storageName}`);
@@ -1901,10 +1576,6 @@ export class Matterbridge extends EventEmitter {
1901
1576
  }
1902
1577
  }
1903
1578
  }
1904
- /**
1905
- * Stops the matter storage.
1906
- * @returns {Promise<void>} A promise that resolves when the storage is stopped.
1907
- */
1908
1579
  async stopMatterStorage() {
1909
1580
  this.log.debug('Stopping storage');
1910
1581
  await this.storageManager?.close();
@@ -1913,14 +1584,8 @@ export class Matterbridge extends EventEmitter {
1913
1584
  this.matterbridgeContext = undefined;
1914
1585
  this.mattercontrollerContext = undefined;
1915
1586
  }
1916
- /**
1917
- * Creates a Matter server using the provided storage manager and the provided mdnsInterface.
1918
- * @param storageManager The storage manager to be used by the Matter server.
1919
- *
1920
- */
1921
1587
  createMatterServer(storageManager) {
1922
1588
  this.log.debug('Creating matter server');
1923
- // Validate mdnsInterface
1924
1589
  if (this.mdnsInterface) {
1925
1590
  const networkInterfaces = os.networkInterfaces();
1926
1591
  const availableInterfaces = Object.keys(networkInterfaces);
@@ -1936,10 +1601,6 @@ export class Matterbridge extends EventEmitter {
1936
1601
  this.log.debug(`Created matter server with mdnsInterface: ${this.mdnsInterface ?? 'all available interfaces'}`);
1937
1602
  return matterServer;
1938
1603
  }
1939
- /**
1940
- * Starts the Matter server.
1941
- * If the Matter server is not initialized, it logs an error and performs cleanup.
1942
- */
1943
1604
  async startMatterServer() {
1944
1605
  if (!this.matterServer) {
1945
1606
  this.log.error('No matter server initialized');
@@ -1949,11 +1610,7 @@ export class Matterbridge extends EventEmitter {
1949
1610
  this.log.debug('Starting matter server...');
1950
1611
  await this.matterServer.start();
1951
1612
  this.log.debug('Started matter server');
1952
- // this.commissioningServer?.getRootEndpoint() && logEndpoint(this.commissioningServer?.getRootEndpoint());
1953
1613
  }
1954
- /**
1955
- * Stops the Matter server, commissioningServer and commissioningController.
1956
- */
1957
1614
  async stopMatterServer() {
1958
1615
  this.log.debug('Stopping matter commissioningServer');
1959
1616
  await this.commissioningServer?.close();
@@ -1967,78 +1624,22 @@ export class Matterbridge extends EventEmitter {
1967
1624
  this.matterAggregator = undefined;
1968
1625
  this.matterServer = undefined;
1969
1626
  }
1970
- /**
1971
- * Creates a Matter Aggregator.
1972
- * @param {StorageContext} context - The storage context.
1973
- * @returns {Aggregator} - The created Matter Aggregator.
1974
- */
1975
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1976
1627
  async createMatterAggregator(context, pluginName) {
1977
- /*
1978
- const random = randomBytes(8).toString('hex');
1979
- await context.set('aggregatorSerialNumber', await context.get('aggregatorSerialNumber', random));
1980
- await context.set('aggregatorUniqueId', await context.get('aggregatorUniqueId', random));
1981
-
1982
- this.log.debug(`Creating matter aggregator for plugin ${plg}${pluginName}${db} with uniqueId ${await context.get<string>('aggregatorUniqueId')} serialNumber ${await context.get<string>('aggregatorSerialNumber')}`);
1983
- 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')}`);
1984
- 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')}`);
1985
- */
1986
1628
  const matterAggregator = new Aggregator();
1987
- /*
1988
- matterAggregator.addClusterServer(
1989
- ClusterServer(
1990
- BasicInformationCluster,
1991
- {
1992
- dataModelRevision: 1,
1993
- location: 'FR',
1994
- vendorId: VendorId(0xfff1),
1995
- vendorName: 'Matterbridge',
1996
- productId: 0x8000,
1997
- productName: 'Matterbridge aggregator',
1998
- productLabel: 'Matterbridge aggregator',
1999
- nodeLabel: 'Matterbridge aggregator',
2000
- serialNumber: await context.get<string>('aggregatorSerialNumber'),
2001
- uniqueId: await context.get<string>('aggregatorUniqueId'),
2002
- softwareVersion: await context.get<number>('softwareVersion', 1),
2003
- softwareVersionString: await context.get<string>('softwareVersionString', '1.0.0'),
2004
- hardwareVersion: await context.get<number>('hardwareVersion', 1),
2005
- hardwareVersionString: await context.get<string>('hardwareVersionString', '1.0.0'),
2006
- reachable: true,
2007
- capabilityMinima: { caseSessionsPerFabric: 3, subscriptionsPerFabric: 3 },
2008
- specificationVersion: Specification.SPECIFICATION_VERSION,
2009
- maxPathsPerInvoke: 1,
2010
- },
2011
- {},
2012
- {
2013
- startUp: true,
2014
- shutDown: true,
2015
- leave: true,
2016
- reachableChanged: true,
2017
- },
2018
- ),
2019
- );
2020
- */
2021
1629
  return matterAggregator;
2022
1630
  }
2023
- /**
2024
- * Creates a matter commissioning server.
2025
- *
2026
- * @param {StorageContext} context - The storage context.
2027
- * @param {string} pluginName - The name of the commissioning server.
2028
- * @returns {CommissioningServer} The created commissioning server.
2029
- */
2030
1631
  async createCommisioningServer(context, pluginName) {
2031
1632
  this.log.debug(`Creating matter commissioning server for plugin ${plg}${pluginName}${db}`);
2032
1633
  const deviceName = await context.get('deviceName');
2033
1634
  const deviceType = await context.get('deviceType');
2034
1635
  const vendorId = await context.get('vendorId');
2035
- const vendorName = await context.get('vendorName'); // Home app = Manufacturer
1636
+ const vendorName = await context.get('vendorName');
2036
1637
  const productId = await context.get('productId');
2037
- const productName = await context.get('productName'); // Home app = Model
1638
+ const productName = await context.get('productName');
2038
1639
  const serialNumber = await context.get('serialNumber');
2039
1640
  const uniqueId = await context.get('uniqueId');
2040
1641
  const softwareVersion = await context.get('softwareVersion', 1);
2041
- const softwareVersionString = await context.get('softwareVersionString', '1.0.0'); // Home app = Firmware Revision
1642
+ const softwareVersionString = await context.get('softwareVersionString', '1.0.0');
2042
1643
  const hardwareVersion = await context.get('hardwareVersion', 1);
2043
1644
  const hardwareVersionString = await context.get('hardwareVersionString', '1.0.0');
2044
1645
  this.log.debug(`Creating matter commissioning server for plugin ${plg}${pluginName}${db} with deviceName '${deviceName}' deviceType ${deviceType}(0x${deviceType.toString(16).padStart(4, '0')})`);
@@ -2046,7 +1647,6 @@ export class Matterbridge extends EventEmitter {
2046
1647
  this.log.debug(`Creating matter commissioning server for plugin ${plg}${pluginName}${db} with softwareVersion ${softwareVersion} softwareVersionString ${softwareVersionString}`);
2047
1648
  this.log.debug(`Creating matter commissioning server for plugin ${plg}${pluginName}${db} with hardwareVersion ${hardwareVersion} hardwareVersionString ${hardwareVersionString}`);
2048
1649
  this.log.debug(`Creating matter commissioning server for plugin ${plg}${pluginName}${db} with nodeLabel '${productName}' port ${this.port} passcode ${this.passcode} discriminator ${this.discriminator}`);
2049
- // Validate ipv4address
2050
1650
  if (this.ipv4address) {
2051
1651
  const networkInterfaces = os.networkInterfaces();
2052
1652
  const availableAddresses = Object.values(networkInterfaces)
@@ -2061,7 +1661,6 @@ export class Matterbridge extends EventEmitter {
2061
1661
  this.log.info(`Using ipv4address '${this.ipv4address}' for the Matter commissioning server.`);
2062
1662
  }
2063
1663
  }
2064
- // Validate ipv6address
2065
1664
  if (this.ipv6address) {
2066
1665
  const networkInterfaces = os.networkInterfaces();
2067
1666
  const availableAddresses = Object.values(networkInterfaces)
@@ -2092,7 +1691,7 @@ export class Matterbridge extends EventEmitter {
2092
1691
  nodeLabel: productName,
2093
1692
  productLabel: productName,
2094
1693
  softwareVersion,
2095
- softwareVersionString, // Home app = Firmware Revision
1694
+ softwareVersionString,
2096
1695
  hardwareVersion,
2097
1696
  hardwareVersionString,
2098
1697
  uniqueId,
@@ -2188,24 +1787,6 @@ export class Matterbridge extends EventEmitter {
2188
1787
  commissioningServer.addCommandHandler('testEventTrigger', async ({ request: { enableKey, eventTrigger } }) => this.log.info(`testEventTrigger called on GeneralDiagnostic cluster: ${enableKey} ${eventTrigger}`));
2189
1788
  return commissioningServer;
2190
1789
  }
2191
- /**
2192
- * Creates a commissioning server storage context.
2193
- *
2194
- * @param pluginName - The name of the plugin.
2195
- * @param deviceName - The name of the device.
2196
- * @param deviceType - The type of the device.
2197
- * @param vendorId - The vendor ID.
2198
- * @param vendorName - The vendor name.
2199
- * @param productId - The product ID.
2200
- * @param productName - The product name.
2201
- * @param serialNumber - The serial number of the device (optional).
2202
- * @param uniqueId - The unique ID of the device (optional).
2203
- * @param softwareVersion - The software version of the device (optional).
2204
- * @param softwareVersionString - The software version string of the device (optional).
2205
- * @param hardwareVersion - The hardware version of the device (optional).
2206
- * @param hardwareVersionString - The hardware version string of the device (optional).
2207
- * @returns The storage context for the commissioning server.
2208
- */
2209
1790
  async createCommissioningServerContext(pluginName, deviceName, deviceType, vendorId, vendorName, productId, productName) {
2210
1791
  if (!this.storageManager)
2211
1792
  throw new Error('No storage manager initialized');
@@ -2233,13 +1814,6 @@ export class Matterbridge extends EventEmitter {
2233
1814
  this.log.debug(`- hardwareVersion: ${await storageContext.get('hardwareVersion')} hardwareVersionString: ${await storageContext.get('hardwareVersionString')}`);
2234
1815
  return storageContext;
2235
1816
  }
2236
- /**
2237
- * Imports the commissioning server context for a specific plugin and device.
2238
- * @param pluginName - The name of the plugin.
2239
- * @param device - The MatterbridgeDevice object representing the device.
2240
- * @returns The commissioning server context.
2241
- * @throws Error if the BasicInformationCluster is not found.
2242
- */
2243
1817
  async importCommissioningServerContext(pluginName, device) {
2244
1818
  this.log.debug(`Importing matter commissioning server storage context from device for ${plg}${pluginName}${db}`);
2245
1819
  const basic = device.getClusterServer(BasicInformationCluster);
@@ -2274,14 +1848,6 @@ export class Matterbridge extends EventEmitter {
2274
1848
  this.log.debug(`- hardwareVersion: ${await storageContext.get('hardwareVersion')} hardwareVersionString: ${await storageContext.get('hardwareVersionString')}`);
2275
1849
  return storageContext;
2276
1850
  }
2277
- /**
2278
- * Shows the commissioning server QR code for a given plugin.
2279
- * @param {CommissioningServer} commissioningServer - The commissioning server instance.
2280
- * @param {StorageContext} storageContext - The storage context instance.
2281
- * @param {NodeStorage} nodeContext - The node storage instance.
2282
- * @param {string} pluginName - The name of the plugin of Matterbridge in bridge mode.
2283
- * @returns {Promise<void>} - A promise that resolves when the QR code is shown.
2284
- */
2285
1851
  async showCommissioningQRCode(commissioningServer, storageContext, nodeContext, pluginName) {
2286
1852
  if (!commissioningServer || !storageContext || !nodeContext || !pluginName) {
2287
1853
  this.log.error(`showCommissioningQRCode error: commissioningServer: ${!commissioningServer} storageContext: ${!storageContext} nodeContext: ${!nodeContext} pluginName: ${pluginName}`);
@@ -2292,8 +1858,7 @@ export class Matterbridge extends EventEmitter {
2292
1858
  const { qrPairingCode, manualPairingCode } = commissioningServer.getPairingCode();
2293
1859
  const QrCode = new QrCodeSchema();
2294
1860
  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`);
2295
- // eslint-disable-next-line no-console
2296
- if (this.log.logLevel === "debug" /* LogLevel.DEBUG */ || this.log.logLevel === "info" /* LogLevel.INFO */)
1861
+ if (this.log.logLevel === "debug" || this.log.logLevel === "info")
2297
1862
  console.log(`${QrCode.encode(qrPairingCode)}\n`);
2298
1863
  this.log.info(`${plg}${pluginName}${nf} \n\nqrPairingCode: ${qrPairingCode} \n\nManual pairing code: ${manualPairingCode}\n`);
2299
1864
  if (pluginName === 'Matterbridge') {
@@ -2340,12 +1905,6 @@ export class Matterbridge extends EventEmitter {
2340
1905
  }
2341
1906
  this.wssSendRefreshRequired();
2342
1907
  }
2343
- /**
2344
- * Sanitizes the fabric information by converting bigint properties to string cause res.json doesn't know bigint.
2345
- *
2346
- * @param fabricInfo - The array of exposed fabric information objects.
2347
- * @returns An array of sanitized exposed fabric information objects.
2348
- */
2349
1908
  sanitizeFabricInformations(fabricInfo) {
2350
1909
  return fabricInfo.map((info) => {
2351
1910
  return {
@@ -2359,12 +1918,6 @@ export class Matterbridge extends EventEmitter {
2359
1918
  };
2360
1919
  });
2361
1920
  }
2362
- /**
2363
- * Sanitizes the session information by converting bigint properties to string.
2364
- *
2365
- * @param sessionInfo - The array of session information objects.
2366
- * @returns An array of sanitized session information objects.
2367
- */
2368
1921
  sanitizeSessionInformation(sessionInfo) {
2369
1922
  return sessionInfo
2370
1923
  .filter((session) => session.isPeerActive)
@@ -2392,12 +1945,6 @@ export class Matterbridge extends EventEmitter {
2392
1945
  };
2393
1946
  });
2394
1947
  }
2395
- /**
2396
- * Sets the reachability of a commissioning server and trigger.
2397
- *
2398
- * @param {CommissioningServer} commissioningServer - The commissioning server to set the reachability for.
2399
- * @param {boolean} reachable - The new reachability status.
2400
- */
2401
1948
  setCommissioningServerReachability(commissioningServer, reachable) {
2402
1949
  const basicInformationCluster = commissioningServer?.getRootClusterServer(BasicInformationCluster);
2403
1950
  if (basicInformationCluster && basicInformationCluster.attributes.reachable !== undefined)
@@ -2405,11 +1952,6 @@ export class Matterbridge extends EventEmitter {
2405
1952
  if (basicInformationCluster && basicInformationCluster.triggerReachableChangedEvent)
2406
1953
  basicInformationCluster.triggerReachableChangedEvent({ reachableNewValue: reachable });
2407
1954
  }
2408
- /**
2409
- * Sets the reachability of the specified matter aggregator and its bridged devices and trigger.
2410
- * @param {Aggregator} matterAggregator - The matter aggregator to set the reachability for.
2411
- * @param {boolean} reachable - A boolean indicating the reachability status to set.
2412
- */
2413
1955
  setAggregatorReachability(matterAggregator, reachable) {
2414
1956
  const basicInformationCluster = matterAggregator.getClusterServer(BasicInformationCluster);
2415
1957
  if (basicInformationCluster && basicInformationCluster.attributes.reachable !== undefined)
@@ -2422,12 +1964,6 @@ export class Matterbridge extends EventEmitter {
2422
1964
  device.getClusterServer(BridgedDeviceBasicInformationCluster)?.triggerReachableChangedEvent({ reachableNewValue: reachable });
2423
1965
  });
2424
1966
  }
2425
- /**
2426
- * Sets the reachability of a device and trigger.
2427
- *
2428
- * @param {MatterbridgeDevice} device - The device to set the reachability for.
2429
- * @param {boolean} reachable - The new reachability status of the device.
2430
- */
2431
1967
  setDeviceReachability(device, reachable) {
2432
1968
  const basicInformationCluster = device.getClusterServer(BasicInformationCluster);
2433
1969
  if (basicInformationCluster && basicInformationCluster.attributes.reachable !== undefined)
@@ -2476,10 +2012,6 @@ export class Matterbridge extends EventEmitter {
2476
2012
  }
2477
2013
  return vendorName;
2478
2014
  };
2479
- /**
2480
- * Retrieves the base registered plugins sanitized for res.json().
2481
- * @returns {BaseRegisteredPlugin[]} A promise that resolves to an array of BaseRegisteredPlugin objects.
2482
- */
2483
2015
  async getBaseRegisteredPlugins() {
2484
2016
  const baseRegisteredPlugins = [];
2485
2017
  for (const plugin of this.plugins) {
@@ -2511,36 +2043,13 @@ export class Matterbridge extends EventEmitter {
2511
2043
  }
2512
2044
  return baseRegisteredPlugins;
2513
2045
  }
2514
- /**
2515
- * Spawns a child process with the given command and arguments.
2516
- * @param {string} command - The command to execute.
2517
- * @param {string[]} args - The arguments to pass to the command (default: []).
2518
- * @returns {Promise<boolean>} A promise that resolves when the child process exits successfully, or rejects if there is an error.
2519
- */
2520
2046
  async spawnCommand(command, args = []) {
2521
- /*
2522
- npm > npm.cmd on windows
2523
- cmd.exe ['dir'] on windows
2524
- await this.spawnCommand('npm', ['install', '-g', 'matterbridge']);
2525
- process.on('unhandledRejection', (reason, promise) => {
2526
- this.log.error('Unhandled Rejection at:', promise, 'reason:', reason);
2527
- });
2528
-
2529
- spawn - [14:27:21.125] [Matterbridge:spawn]: changed 38 packages in 4s
2530
- spawn - [14:27:21.125] [Matterbridge:spawn]: 10 packages are looking for funding run `npm fund` for details
2531
- debug - [14:27:21.131] [Matterbridge]: Child process exited with code 0 and signal null
2532
- debug - [14:27:21.131] [Matterbridge]: Child process stdio streams have closed with code 0
2533
- */
2534
2047
  const cmdLine = command + ' ' + args.join(' ');
2535
2048
  if (process.platform === 'win32' && command === 'npm') {
2536
- // Must be spawn('cmd.exe', ['/c', 'npm -g install <package>']);
2537
2049
  const argstring = 'npm ' + args.join(' ');
2538
2050
  args.splice(0, args.length, '/c', argstring);
2539
2051
  command = 'cmd.exe';
2540
2052
  }
2541
- // Decide when using sudo on linux
2542
- // When you need sudo: Spawn stderr: npm error Error: EACCES: permission denied
2543
- // When you don't need sudo: Failed to start child process "npm install -g matterbridge-eve-door": spawn sudo ENOENT
2544
2053
  if (hasParameter('sudo') || (process.platform === 'linux' && command === 'npm' && !hasParameter('docker') && !hasParameter('nosudo'))) {
2545
2054
  args.unshift(command);
2546
2055
  command = 'sudo';
@@ -2598,102 +2107,55 @@ export class Matterbridge extends EventEmitter {
2598
2107
  }
2599
2108
  });
2600
2109
  }
2601
- /**
2602
- * Sends a WebSocket message to all connected clients.
2603
- *
2604
- * @param {string} level - The logger level of the message: debug info notice warn error fatal...
2605
- * @param {string} time - The time string of the message
2606
- * @param {string} name - The logger name of the message
2607
- * @param {string} message - The content of the message.
2608
- */
2609
2110
  wssSendMessage(level, time, name, message) {
2610
2111
  if (!level || !time || !name || !message)
2611
2112
  return;
2612
- // Remove ANSI escape codes from the message
2613
- // eslint-disable-next-line no-control-regex
2614
2113
  message = message.replace(/\x1B\[[0-9;]*[m|s|u|K]/g, '');
2615
- // Remove leading asterisks from the message
2616
2114
  message = message.replace(/^\*+/, '');
2617
- // Replace all occurrences of \t and \n
2618
2115
  message = message.replace(/[\t\n]/g, '');
2619
- // Remove non-printable characters
2620
- // eslint-disable-next-line no-control-regex
2621
2116
  message = message.replace(/[\x00-\x1F\x7F]/g, '');
2622
- // Replace all occurrences of \" with "
2623
2117
  message = message.replace(/\\"/g, '"');
2624
- // Define the maximum allowed length for continuous characters without a space
2625
2118
  const maxContinuousLength = 100;
2626
2119
  const keepStartLength = 20;
2627
2120
  const keepEndLength = 20;
2628
- // Split the message into words
2629
2121
  message = message
2630
2122
  .split(' ')
2631
2123
  .map((word) => {
2632
- // If the word length exceeds the max continuous length, insert spaces and truncate
2633
2124
  if (word.length > maxContinuousLength) {
2634
2125
  return word.slice(0, keepStartLength) + ' ... ' + word.slice(-keepEndLength);
2635
2126
  }
2636
2127
  return word;
2637
2128
  })
2638
2129
  .join(' ');
2639
- // Send the message to all connected clients
2640
2130
  this.webSocketServer?.clients.forEach((client) => {
2641
2131
  if (client.readyState === WebSocket.OPEN) {
2642
2132
  client.send(JSON.stringify({ id: WS_ID_LOG, src: 'Matterbridge', level, time, name, message }));
2643
2133
  }
2644
2134
  });
2645
2135
  }
2646
- /**
2647
- * Sends a need to refresh WebSocket message to all connected clients.
2648
- *
2649
- */
2650
2136
  wssSendRefreshRequired() {
2651
2137
  this.matterbridgeInformation.refreshRequired = true;
2652
- // Send the message to all connected clients
2653
2138
  this.webSocketServer?.clients.forEach((client) => {
2654
2139
  if (client.readyState === WebSocket.OPEN) {
2655
2140
  client.send(JSON.stringify({ id: WS_ID_REFRESH_NEEDED, src: 'Matterbridge', dst: 'Matterbridge', method: 'refresh_required', params: {} }));
2656
2141
  }
2657
2142
  });
2658
2143
  }
2659
- /**
2660
- * Sends a need to restart WebSocket message to all connected clients.
2661
- *
2662
- */
2663
2144
  wssSendRestartRequired() {
2664
2145
  this.matterbridgeInformation.restartRequired = true;
2665
- // Send the message to all connected clients
2666
2146
  this.webSocketServer?.clients.forEach((client) => {
2667
2147
  if (client.readyState === WebSocket.OPEN) {
2668
2148
  client.send(JSON.stringify({ id: WS_ID_RESTART_NEEDED, src: 'Matterbridge', dst: 'Matterbridge', method: 'restart_required', params: {} }));
2669
2149
  }
2670
2150
  });
2671
2151
  }
2672
- /**
2673
- * Initializes the frontend of Matterbridge.
2674
- *
2675
- * @param port The port number to run the frontend server on. Default is 8283.
2676
- */
2677
2152
  async initializeFrontend(port = 8283) {
2678
2153
  let initializeError = false;
2679
2154
  this.log.debug(`Initializing the frontend ${hasParameter('ssl') ? 'https' : 'http'} server on port ${YELLOW}${port}${db}`);
2680
- // Create the express app that serves the frontend
2681
2155
  this.expressApp = express();
2682
- // Log all requests to the server for debugging
2683
- /*
2684
- if (hasParameter('homedir')) {
2685
- this.expressApp.use((req, res, next) => {
2686
- this.log.debug(`Received request on expressApp: ${req.method} ${req.url}`);
2687
- next();
2688
- });
2689
- }
2690
- */
2691
- // Serve static files from '/static' endpoint
2692
2156
  this.expressApp.use(express.static(path.join(this.rootDirectory, 'frontend/build')));
2693
2157
  if (!hasParameter('ssl')) {
2694
- // Create an HTTP server and attach the express app
2695
2158
  this.httpServer = createServer(this.expressApp);
2696
- // Listen on the specified port
2697
2159
  if (hasParameter('ingress')) {
2698
2160
  this.httpServer.listen(port, '0.0.0.0', () => {
2699
2161
  this.log.info(`The frontend http server is listening on ${UNDERLINE}http://0.0.0.0:${port}${UNDERLINEOFF}${rs}`);
@@ -2707,7 +2169,6 @@ export class Matterbridge extends EventEmitter {
2707
2169
  this.log.info(`The frontend http server is listening on ${UNDERLINE}http://[${this.systemInformation.ipv6Address}]:${port}${UNDERLINEOFF}${rs}`);
2708
2170
  });
2709
2171
  }
2710
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
2711
2172
  this.httpServer.on('error', (error) => {
2712
2173
  this.log.error(`Frontend http server error listening on ${port}`);
2713
2174
  switch (error.code) {
@@ -2723,7 +2184,6 @@ export class Matterbridge extends EventEmitter {
2723
2184
  });
2724
2185
  }
2725
2186
  else {
2726
- // Load the SSL certificate, the private key and optionally the CA certificate
2727
2187
  let cert;
2728
2188
  try {
2729
2189
  cert = await fs.readFile(path.join(this.matterbridgeDirectory, 'certs/cert.pem'), 'utf8');
@@ -2751,9 +2211,7 @@ export class Matterbridge extends EventEmitter {
2751
2211
  this.log.info(`CA certificate file ${path.join(this.matterbridgeDirectory, 'certs/ca.pem')} not loaded: ${error}`);
2752
2212
  }
2753
2213
  const serverOptions = { cert, key, ca };
2754
- // Create an HTTPS server with the SSL certificate and private key (ca is optional) and attach the express app
2755
2214
  this.httpsServer = https.createServer(serverOptions, this.expressApp);
2756
- // Listen on the specified port
2757
2215
  if (hasParameter('ingress')) {
2758
2216
  this.httpsServer.listen(port, '0.0.0.0', () => {
2759
2217
  this.log.info(`The frontend https server is listening on ${UNDERLINE}https://0.0.0.0:${port}${UNDERLINEOFF}${rs}`);
@@ -2767,7 +2225,6 @@ export class Matterbridge extends EventEmitter {
2767
2225
  this.log.info(`The frontend https server is listening on ${UNDERLINE}https://[${this.systemInformation.ipv6Address}]:${port}${UNDERLINEOFF}${rs}`);
2768
2226
  });
2769
2227
  }
2770
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
2771
2228
  this.httpsServer.on('error', (error) => {
2772
2229
  this.log.error(`Frontend https server error listening on ${port}`);
2773
2230
  switch (error.code) {
@@ -2784,13 +2241,12 @@ export class Matterbridge extends EventEmitter {
2784
2241
  }
2785
2242
  if (initializeError)
2786
2243
  return;
2787
- // Createe a WebSocket server and attach it to the http or https server
2788
2244
  const wssPort = port;
2789
2245
  const wssHost = hasParameter('ssl') ? `wss://${this.systemInformation.ipv4Address}:${wssPort}` : `ws://${this.systemInformation.ipv4Address}:${wssPort}`;
2790
2246
  this.webSocketServer = new WebSocketServer(hasParameter('ssl') ? { server: this.httpsServer } : { server: this.httpServer });
2791
2247
  this.webSocketServer.on('connection', (ws, request) => {
2792
2248
  const clientIp = request.socket.remoteAddress;
2793
- AnsiLogger.setGlobalCallback(this.wssSendMessage.bind(this), "debug" /* LogLevel.DEBUG */);
2249
+ AnsiLogger.setGlobalCallback(this.wssSendMessage.bind(this), "debug");
2794
2250
  this.log.info(`WebSocketServer client "${clientIp}" connected to Matterbridge`);
2795
2251
  ws.on('message', (message) => {
2796
2252
  this.log.debug(`WebSocket client message: ${message}`);
@@ -2823,7 +2279,6 @@ export class Matterbridge extends EventEmitter {
2823
2279
  this.webSocketServer.on('error', (ws, error) => {
2824
2280
  this.log.error(`WebSocketServer error: ${error}`);
2825
2281
  });
2826
- // Endpoint to validate login code
2827
2282
  this.expressApp.post('/api/login', express.json(), async (req, res) => {
2828
2283
  const { password } = req.body;
2829
2284
  this.log.debug('The frontend sent /api/login', password);
@@ -2842,14 +2297,12 @@ export class Matterbridge extends EventEmitter {
2842
2297
  this.log.warn('/api/login error wrong password');
2843
2298
  res.json({ valid: false });
2844
2299
  }
2845
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
2846
2300
  }
2847
2301
  catch (error) {
2848
2302
  this.log.error('/api/login error getting password');
2849
2303
  res.json({ valid: false });
2850
2304
  }
2851
2305
  });
2852
- // Endpoint to provide settings
2853
2306
  this.expressApp.get('/api/settings', express.json(), async (req, res) => {
2854
2307
  this.log.debug('The frontend sent /api/settings');
2855
2308
  this.matterbridgeInformation.bridgeMode = this.bridgeMode;
@@ -2867,17 +2320,13 @@ export class Matterbridge extends EventEmitter {
2867
2320
  this.matterbridgeInformation.matterbridgeSessionInformations = Array.from(this.matterbridgeSessionInformations.values());
2868
2321
  this.matterbridgeInformation.profile = this.profile;
2869
2322
  const response = { wssHost, ssl: hasParameter('ssl'), systemInformation: this.systemInformation, matterbridgeInformation: this.matterbridgeInformation };
2870
- // this.log.debug('Response:', debugStringify(response));
2871
2323
  res.json(response);
2872
2324
  });
2873
- // Endpoint to provide plugins
2874
2325
  this.expressApp.get('/api/plugins', async (req, res) => {
2875
2326
  this.log.debug('The frontend sent /api/plugins');
2876
2327
  const response = await this.getBaseRegisteredPlugins();
2877
- // this.log.debug('Response:', debugStringify(response));
2878
2328
  res.json(response);
2879
2329
  });
2880
- // Endpoint to provide devices
2881
2330
  this.expressApp.get('/api/devices', (req, res) => {
2882
2331
  this.log.debug('The frontend sent /api/devices');
2883
2332
  const data = [];
@@ -2905,10 +2354,8 @@ export class Matterbridge extends EventEmitter {
2905
2354
  cluster: cluster,
2906
2355
  });
2907
2356
  });
2908
- // this.log.debug('Response:', debugStringify(data));
2909
2357
  res.json(data);
2910
2358
  });
2911
- // Endpoint to provide the cluster servers of the devices
2912
2359
  this.expressApp.get('/api/devices_clusters/:selectedPluginName/:selectedDeviceEndpoint', (req, res) => {
2913
2360
  const selectedPluginName = req.params.selectedPluginName;
2914
2361
  const selectedDeviceEndpoint = parseInt(req.params.selectedDeviceEndpoint, 10);
@@ -2928,7 +2375,6 @@ export class Matterbridge extends EventEmitter {
2928
2375
  Object.entries(clusterServer.attributes).forEach(([key, value]) => {
2929
2376
  if (clusterServer.name === 'EveHistory')
2930
2377
  return;
2931
- // this.log.debug(`***--clusterServer: ${clusterServer.name}(${clusterServer.id}) attribute:${key}(${value.id}) ${value.isFixed} ${value.isWritable} ${value.isWritable}`);
2932
2378
  let attributeValue;
2933
2379
  try {
2934
2380
  if (typeof value.getLocal() === 'object')
@@ -2939,7 +2385,6 @@ export class Matterbridge extends EventEmitter {
2939
2385
  catch (error) {
2940
2386
  attributeValue = 'Fabric-Scoped';
2941
2387
  this.log.debug(`GetLocal value ${error} in clusterServer: ${clusterServer.name}(${clusterServer.id}) attribute: ${key}(${value.id})`);
2942
- // console.log(error);
2943
2388
  }
2944
2389
  data.push({
2945
2390
  endpoint: device.number ? device.number.toString() : '...',
@@ -2952,14 +2397,12 @@ export class Matterbridge extends EventEmitter {
2952
2397
  });
2953
2398
  });
2954
2399
  device.getChildEndpoints().forEach((childEndpoint) => {
2955
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
2956
2400
  const name = this.edge ? childEndpoint.endpoint?.id : childEndpoint.uniqueStorageKey;
2957
2401
  const clusterServers = childEndpoint.getAllClusterServers();
2958
2402
  clusterServers.forEach((clusterServer) => {
2959
2403
  Object.entries(clusterServer.attributes).forEach(([key, value]) => {
2960
2404
  if (clusterServer.name === 'EveHistory')
2961
2405
  return;
2962
- // this.log.debug(`***--clusterServer: ${clusterServer.name}(${clusterServer.id}) attribute:${key}(${value.id}) ${value.isFixed} ${value.isWritable} ${value.isWritable}`);
2963
2406
  let attributeValue;
2964
2407
  try {
2965
2408
  if (typeof value.getLocal() === 'object')
@@ -2970,7 +2413,6 @@ export class Matterbridge extends EventEmitter {
2970
2413
  catch (error) {
2971
2414
  attributeValue = 'Unavailable';
2972
2415
  this.log.debug(`GetLocal error ${error} in clusterServer: ${clusterServer.name}(${clusterServer.id}) attribute: ${key}(${value.id})`);
2973
- // console.log(error);
2974
2416
  }
2975
2417
  data.push({
2976
2418
  endpoint: (childEndpoint.number ? childEndpoint.number.toString() : '...') + (name ? ' (' + name + ')' : ''),
@@ -2987,7 +2429,6 @@ export class Matterbridge extends EventEmitter {
2987
2429
  });
2988
2430
  res.json(data);
2989
2431
  });
2990
- // Endpoint to view the log
2991
2432
  this.expressApp.get('/api/view-log', async (req, res) => {
2992
2433
  this.log.debug('The frontend sent /api/log');
2993
2434
  try {
@@ -3000,12 +2441,10 @@ export class Matterbridge extends EventEmitter {
3000
2441
  res.status(500).send('Error reading log file');
3001
2442
  }
3002
2443
  });
3003
- // Endpoint to download the matterbridge log
3004
2444
  this.expressApp.get('/api/download-mblog', async (req, res) => {
3005
2445
  this.log.debug('The frontend sent /api/download-mblog');
3006
2446
  try {
3007
2447
  await fs.access(path.join(this.matterbridgeDirectory, this.matterbrideLoggerFile), fs.constants.F_OK);
3008
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
3009
2448
  }
3010
2449
  catch (error) {
3011
2450
  fs.appendFile(path.join(this.matterbridgeDirectory, this.matterbrideLoggerFile), 'Enable the log on file in the settings to enable the file logger');
@@ -3017,12 +2456,10 @@ export class Matterbridge extends EventEmitter {
3017
2456
  }
3018
2457
  });
3019
2458
  });
3020
- // Endpoint to download the matter log
3021
2459
  this.expressApp.get('/api/download-mjlog', async (req, res) => {
3022
2460
  this.log.debug('The frontend sent /api/download-mjlog');
3023
2461
  try {
3024
2462
  await fs.access(path.join(this.matterbridgeDirectory, this.matterLoggerFile), fs.constants.F_OK);
3025
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
3026
2463
  }
3027
2464
  catch (error) {
3028
2465
  fs.appendFile(path.join(this.matterbridgeDirectory, this.matterLoggerFile), 'Enable the log on file in the settings to enable the file logger');
@@ -3034,7 +2471,6 @@ export class Matterbridge extends EventEmitter {
3034
2471
  }
3035
2472
  });
3036
2473
  });
3037
- // Endpoint to download the matter storage file
3038
2474
  this.expressApp.get('/api/download-mjstorage', (req, res) => {
3039
2475
  this.log.debug('The frontend sent /api/download-mjstorage');
3040
2476
  res.download(path.join(this.matterbridgeDirectory, this.matterStorageName), 'matterbridge.json', (error) => {
@@ -3044,7 +2480,6 @@ export class Matterbridge extends EventEmitter {
3044
2480
  }
3045
2481
  });
3046
2482
  });
3047
- // Endpoint to download the matterbridge storage directory
3048
2483
  this.expressApp.get('/api/download-mbstorage', async (req, res) => {
3049
2484
  this.log.debug('The frontend sent /api/download-mbstorage');
3050
2485
  await createZip(path.join(os.tmpdir(), `matterbridge.${this.nodeStorageName}.zip`), path.join(this.matterbridgeDirectory, this.nodeStorageName));
@@ -3055,7 +2490,6 @@ export class Matterbridge extends EventEmitter {
3055
2490
  }
3056
2491
  });
3057
2492
  });
3058
- // Endpoint to download the matterbridge plugin directory
3059
2493
  this.expressApp.get('/api/download-pluginstorage', async (req, res) => {
3060
2494
  this.log.debug('The frontend sent /api/download-pluginstorage');
3061
2495
  await createZip(path.join(os.tmpdir(), `matterbridge.pluginstorage.zip`), this.matterbridgePluginDirectory);
@@ -3066,11 +2500,9 @@ export class Matterbridge extends EventEmitter {
3066
2500
  }
3067
2501
  });
3068
2502
  });
3069
- // Endpoint to download the matterbridge plugin config files
3070
2503
  this.expressApp.get('/api/download-pluginconfig', async (req, res) => {
3071
2504
  this.log.debug('The frontend sent /api/download-pluginconfig');
3072
2505
  await createZip(path.join(os.tmpdir(), `matterbridge.pluginconfig.zip`), path.relative(process.cwd(), path.join(this.matterbridgeDirectory, '*.config.json')));
3073
- // 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')));
3074
2506
  res.download(path.join(os.tmpdir(), `matterbridge.pluginconfig.zip`), `matterbridge.pluginconfig.zip`, (error) => {
3075
2507
  if (error) {
3076
2508
  this.log.error(`Error downloading file matterbridge.pluginstorage.zip: ${error instanceof Error ? error.message : error}`);
@@ -3078,7 +2510,6 @@ export class Matterbridge extends EventEmitter {
3078
2510
  }
3079
2511
  });
3080
2512
  });
3081
- // Endpoint to download the matterbridge plugin config files
3082
2513
  this.expressApp.get('/api/download-backup', async (req, res) => {
3083
2514
  this.log.debug('The frontend sent /api/download-backup');
3084
2515
  res.download(path.join(os.tmpdir(), `matterbridge.backup.zip`), `matterbridge.backup.zip`, (error) => {
@@ -3088,7 +2519,6 @@ export class Matterbridge extends EventEmitter {
3088
2519
  }
3089
2520
  });
3090
2521
  });
3091
- // Endpoint to receive commands
3092
2522
  this.expressApp.post('/api/command/:command/:param', express.json(), async (req, res) => {
3093
2523
  const command = req.params.command;
3094
2524
  let param = req.params.param;
@@ -3098,15 +2528,13 @@ export class Matterbridge extends EventEmitter {
3098
2528
  return;
3099
2529
  }
3100
2530
  this.log.debug(`Received frontend command: ${command}:${param}`);
3101
- // Handle the command setpassword from Settings
3102
2531
  if (command === 'setpassword') {
3103
- const password = param.slice(1, -1); // Remove the first and last characters
2532
+ const password = param.slice(1, -1);
3104
2533
  this.log.debug('setpassword', param, password);
3105
2534
  await this.nodeContext?.set('password', password);
3106
2535
  res.json({ message: 'Command received' });
3107
2536
  return;
3108
2537
  }
3109
- // Handle the command setbridgemode from Settings
3110
2538
  if (command === 'setbridgemode') {
3111
2539
  this.log.debug(`setbridgemode: ${param}`);
3112
2540
  this.wssSendRestartRequired();
@@ -3114,7 +2542,6 @@ export class Matterbridge extends EventEmitter {
3114
2542
  res.json({ message: 'Command received' });
3115
2543
  return;
3116
2544
  }
3117
- // Handle the command backup from Settings
3118
2545
  if (command === 'backup') {
3119
2546
  this.log.notice(`Prepairing the backup...`);
3120
2547
  await createZip(path.join(os.tmpdir(), `matterbridge.backup.zip`), path.join(this.matterbridgeDirectory), path.join(this.matterbridgePluginDirectory));
@@ -3122,26 +2549,25 @@ export class Matterbridge extends EventEmitter {
3122
2549
  res.json({ message: 'Command received' });
3123
2550
  return;
3124
2551
  }
3125
- // Handle the command setmbloglevel from Settings
3126
2552
  if (command === 'setmbloglevel') {
3127
2553
  this.log.debug('Matterbridge log level:', param);
3128
2554
  if (param === 'Debug') {
3129
- this.log.logLevel = "debug" /* LogLevel.DEBUG */;
2555
+ this.log.logLevel = "debug";
3130
2556
  }
3131
2557
  else if (param === 'Info') {
3132
- this.log.logLevel = "info" /* LogLevel.INFO */;
2558
+ this.log.logLevel = "info";
3133
2559
  }
3134
2560
  else if (param === 'Notice') {
3135
- this.log.logLevel = "notice" /* LogLevel.NOTICE */;
2561
+ this.log.logLevel = "notice";
3136
2562
  }
3137
2563
  else if (param === 'Warn') {
3138
- this.log.logLevel = "warn" /* LogLevel.WARN */;
2564
+ this.log.logLevel = "warn";
3139
2565
  }
3140
2566
  else if (param === 'Error') {
3141
- this.log.logLevel = "error" /* LogLevel.ERROR */;
2567
+ this.log.logLevel = "error";
3142
2568
  }
3143
2569
  else if (param === 'Fatal') {
3144
- this.log.logLevel = "fatal" /* LogLevel.FATAL */;
2570
+ this.log.logLevel = "fatal";
3145
2571
  }
3146
2572
  await this.nodeContext?.set('matterbridgeLogLevel', this.log.logLevel);
3147
2573
  MatterbridgeDevice.logLevel = this.log.logLevel;
@@ -3149,13 +2575,12 @@ export class Matterbridge extends EventEmitter {
3149
2575
  for (const plugin of this.plugins) {
3150
2576
  if (!plugin.platform || !plugin.platform.config)
3151
2577
  continue;
3152
- plugin.platform.log.logLevel = plugin.platform.config.debug ? "debug" /* LogLevel.DEBUG */ : this.log.logLevel;
3153
- await plugin.platform.onChangeLoggerLevel(plugin.platform.config.debug ? "debug" /* LogLevel.DEBUG */ : this.log.logLevel);
2578
+ plugin.platform.log.logLevel = plugin.platform.config.debug ? "debug" : this.log.logLevel;
2579
+ await plugin.platform.onChangeLoggerLevel(plugin.platform.config.debug ? "debug" : this.log.logLevel);
3154
2580
  }
3155
2581
  res.json({ message: 'Command received' });
3156
2582
  return;
3157
2583
  }
3158
- // Handle the command setmbloglevel from Settings
3159
2584
  if (command === 'setmjloglevel') {
3160
2585
  this.log.debug('Matter.js log level:', param);
3161
2586
  if (param === 'Debug') {
@@ -3180,47 +2605,41 @@ export class Matterbridge extends EventEmitter {
3180
2605
  res.json({ message: 'Command received' });
3181
2606
  return;
3182
2607
  }
3183
- // Handle the command setmdnsinterface from Settings
3184
2608
  if (command === 'setmdnsinterface') {
3185
- param = param.slice(1, -1); // Remove the first and last characters *mdns*
2609
+ param = param.slice(1, -1);
3186
2610
  this.matterbridgeInformation.mattermdnsinterface = param;
3187
2611
  this.log.debug('Matter.js mdns interface:', param === '' ? 'All interfaces' : param);
3188
2612
  await this.nodeContext?.set('mattermdnsinterface', param);
3189
2613
  res.json({ message: 'Command received' });
3190
2614
  return;
3191
2615
  }
3192
- // Handle the command setipv4address from Settings
3193
2616
  if (command === 'setipv4address') {
3194
- param = param.slice(1, -1); // Remove the first and last characters *ip*
2617
+ param = param.slice(1, -1);
3195
2618
  this.matterbridgeInformation.matteripv4address = param;
3196
2619
  this.log.debug('Matter.js ipv4 address:', param === '' ? 'All ipv4 addresses' : param);
3197
2620
  await this.nodeContext?.set('matteripv4address', param);
3198
2621
  res.json({ message: 'Command received' });
3199
2622
  return;
3200
2623
  }
3201
- // Handle the command setipv6address from Settings
3202
2624
  if (command === 'setipv6address') {
3203
- param = param.slice(1, -1); // Remove the first and last characters *ip*
2625
+ param = param.slice(1, -1);
3204
2626
  this.matterbridgeInformation.matteripv6address = param;
3205
2627
  this.log.debug('Matter.js ipv6 address:', param === '' ? 'All ipv6 addresses' : param);
3206
2628
  await this.nodeContext?.set('matteripv6address', param);
3207
2629
  res.json({ message: 'Command received' });
3208
2630
  return;
3209
2631
  }
3210
- // Handle the command setmbloglevel from Settings
3211
2632
  if (command === 'setmblogfile') {
3212
2633
  this.log.debug('Matterbridge file log:', param);
3213
2634
  this.matterbridgeInformation.fileLogger = param === 'true';
3214
2635
  await this.nodeContext?.set('matterbridgeFileLog', param === 'true');
3215
- // Create the file logger for matterbridge
3216
2636
  if (param === 'true')
3217
- AnsiLogger.setGlobalLogfile(path.join(this.matterbridgeDirectory, this.matterbrideLoggerFile), "debug" /* LogLevel.DEBUG */, true);
2637
+ AnsiLogger.setGlobalLogfile(path.join(this.matterbridgeDirectory, this.matterbrideLoggerFile), "debug", true);
3218
2638
  else
3219
2639
  AnsiLogger.setGlobalLogfile(undefined);
3220
2640
  res.json({ message: 'Command received' });
3221
2641
  return;
3222
2642
  }
3223
- // Handle the command setmbloglevel from Settings
3224
2643
  if (command === 'setmjlogfile') {
3225
2644
  this.log.debug('Matter file log:', param);
3226
2645
  this.matterbridgeInformation.matterFileLogger = param === 'true';
@@ -3247,43 +2666,36 @@ export class Matterbridge extends EventEmitter {
3247
2666
  res.json({ message: 'Command received' });
3248
2667
  return;
3249
2668
  }
3250
- // Handle the command unregister from Settings
3251
2669
  if (command === 'unregister') {
3252
2670
  await this.unregisterAndShutdownProcess();
3253
2671
  res.json({ message: 'Command received' });
3254
2672
  return;
3255
2673
  }
3256
- // Handle the command reset from Settings
3257
2674
  if (command === 'reset') {
3258
2675
  await this.shutdownProcessAndReset();
3259
2676
  res.json({ message: 'Command received' });
3260
2677
  return;
3261
2678
  }
3262
- // Handle the command factoryreset from Settings
3263
2679
  if (command === 'factoryreset') {
3264
2680
  await this.shutdownProcessAndFactoryReset();
3265
2681
  res.json({ message: 'Command received' });
3266
2682
  return;
3267
2683
  }
3268
- // Handle the command shutdown from Header
3269
2684
  if (command === 'shutdown') {
3270
2685
  await this.shutdownProcess();
3271
2686
  res.json({ message: 'Command received' });
3272
2687
  return;
3273
2688
  }
3274
- // Handle the command restart from Header
3275
2689
  if (command === 'restart') {
3276
2690
  await this.restartProcess();
3277
2691
  res.json({ message: 'Command received' });
3278
2692
  return;
3279
2693
  }
3280
- // Handle the command update from Header
3281
2694
  if (command === 'update') {
3282
2695
  this.log.info('Updating matterbridge...');
3283
2696
  try {
3284
2697
  await this.spawnCommand('npm', ['install', '-g', 'matterbridge', '--omit=dev', '--verbose']);
3285
2698
  this.log.info('Matterbridge has been updated. Full restart required.');
3286
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
3287
2699
  }
3288
2700
  catch (error) {
3289
2701
  this.log.error('Error updating matterbridge');
@@ -3293,11 +2705,9 @@ export class Matterbridge extends EventEmitter {
3293
2705
  res.json({ message: 'Command received' });
3294
2706
  return;
3295
2707
  }
3296
- // Handle the command saveconfig from Home
3297
2708
  if (command === 'saveconfig') {
3298
2709
  param = param.replace(/\*/g, '\\');
3299
2710
  this.log.info(`Saving config for plugin ${plg}${param}${nf}...`);
3300
- // console.log('Req.body:', JSON.stringify(req.body, null, 2));
3301
2711
  if (!this.plugins.has(param)) {
3302
2712
  this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
3303
2713
  }
@@ -3311,35 +2721,28 @@ export class Matterbridge extends EventEmitter {
3311
2721
  res.json({ message: 'Command received' });
3312
2722
  return;
3313
2723
  }
3314
- // Handle the command installplugin from Home
3315
2724
  if (command === 'installplugin') {
3316
2725
  param = param.replace(/\*/g, '\\');
3317
2726
  this.log.info(`Installing plugin ${plg}${param}${nf}...`);
3318
2727
  try {
3319
2728
  await this.spawnCommand('npm', ['install', '-g', param, '--omit=dev', '--verbose']);
3320
2729
  this.log.info(`Plugin ${plg}${param}${nf} installed. Full restart required.`);
3321
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
3322
2730
  }
3323
2731
  catch (error) {
3324
2732
  this.log.error(`Error installing plugin ${plg}${param}${er}`);
3325
2733
  }
3326
2734
  this.wssSendRestartRequired();
3327
- // Also add the plugin to matterbridge so no return!
3328
- // res.json({ message: 'Command received' });
3329
- // return;
3330
2735
  }
3331
- // Handle the command addplugin from Home
3332
2736
  if (command === 'addplugin' || command === 'installplugin') {
3333
2737
  param = param.replace(/\*/g, '\\');
3334
2738
  const plugin = await this.plugins.add(param);
3335
2739
  if (plugin) {
3336
- this.plugins.load(plugin, true, 'The plugin has been added', true); // No await do it in the background
2740
+ this.plugins.load(plugin, true, 'The plugin has been added', true);
3337
2741
  }
3338
2742
  res.json({ message: 'Command received' });
3339
2743
  this.wssSendRefreshRequired();
3340
2744
  return;
3341
2745
  }
3342
- // Handle the command removeplugin from Home
3343
2746
  if (command === 'removeplugin') {
3344
2747
  if (!this.plugins.has(param)) {
3345
2748
  this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
@@ -3353,7 +2756,6 @@ export class Matterbridge extends EventEmitter {
3353
2756
  this.wssSendRefreshRequired();
3354
2757
  return;
3355
2758
  }
3356
- // Handle the command enableplugin from Home
3357
2759
  if (command === 'enableplugin') {
3358
2760
  if (!this.plugins.has(param)) {
3359
2761
  this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
@@ -3371,14 +2773,13 @@ export class Matterbridge extends EventEmitter {
3371
2773
  plugin.registeredDevices = undefined;
3372
2774
  plugin.addedDevices = undefined;
3373
2775
  await this.plugins.enable(param);
3374
- this.plugins.load(plugin, true, 'The plugin has been enabled', true); // No await do it in the background
2776
+ this.plugins.load(plugin, true, 'The plugin has been enabled', true);
3375
2777
  }
3376
2778
  }
3377
2779
  res.json({ message: 'Command received' });
3378
2780
  this.wssSendRefreshRequired();
3379
2781
  return;
3380
2782
  }
3381
- // Handle the command disableplugin from Home
3382
2783
  if (command === 'disableplugin') {
3383
2784
  if (!this.plugins.has(param)) {
3384
2785
  this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
@@ -3395,7 +2796,6 @@ export class Matterbridge extends EventEmitter {
3395
2796
  return;
3396
2797
  }
3397
2798
  });
3398
- // Fallback for routing (must be the last route)
3399
2799
  this.expressApp.get('*', (req, res) => {
3400
2800
  this.log.debug('The frontend sent:', req.url);
3401
2801
  this.log.debug('Response send file:', path.join(this.rootDirectory, 'frontend/build/index.html'));
@@ -3403,11 +2803,6 @@ export class Matterbridge extends EventEmitter {
3403
2803
  });
3404
2804
  this.log.debug(`Frontend initialized on port ${YELLOW}${port}${db} static ${UNDERLINE}${path.join(this.rootDirectory, 'frontend/build')}${UNDERLINEOFF}${rs}`);
3405
2805
  }
3406
- /**
3407
- * Retrieves the cluster text description from a given device.
3408
- * @param {MatterbridgeDevice} device - The MatterbridgeDevice object.
3409
- * @returns {string} The attributes description of the cluster servers in the device.
3410
- */
3411
2806
  getClusterTextFromDevice(device) {
3412
2807
  const stringifyUserLabel = (endpoint) => {
3413
2808
  const labelList = endpoint.getClusterServer(UserLabelCluster)?.attributes.labelList.getLocal();
@@ -3430,11 +2825,9 @@ export class Matterbridge extends EventEmitter {
3430
2825
  return '';
3431
2826
  };
3432
2827
  let attributes = '';
3433
- // this.log.debug(`***getClusterTextFromDevice: ${device.deviceName} (${device.name})`);
3434
2828
  const clusterServers = device.getAllClusterServers();
3435
2829
  clusterServers.forEach((clusterServer) => {
3436
2830
  try {
3437
- // this.log.debug(`**--clusterServer: ${clusterServer.id} (${clusterServer.name})`);
3438
2831
  if (clusterServer.name === 'OnOff')
3439
2832
  attributes += `OnOff: ${clusterServer.attributes.onOff.getLocal()} `;
3440
2833
  if (clusterServer.name === 'Switch')
@@ -3485,30 +2878,18 @@ export class Matterbridge extends EventEmitter {
3485
2878
  attributes += `${stringifyFixedLabel(device)} `;
3486
2879
  if (clusterServer.name === 'UserLabel')
3487
2880
  attributes += `${stringifyUserLabel(device)} `;
3488
- // this.log.debug(`*--clusterServer: ${clusterServer.id} (${clusterServer.name})`);
3489
2881
  }
3490
2882
  catch (error) {
3491
2883
  this.log.error(`getClusterTextFromDevice with ${clusterServer.name} error: ${error}`);
3492
2884
  }
3493
2885
  });
3494
- // this.log.debug(`*getClusterTextFromDevice: ${device.deviceName} (${device.name})`);
3495
2886
  return attributes;
3496
2887
  }
3497
- /**
3498
- * Initializes the Matterbridge instance as extension for zigbee2mqtt.
3499
- * @deprecated This method is deprecated and will be removed in a future version.
3500
- *
3501
- * @returns A Promise that resolves when the initialization is complete.
3502
- */
3503
2888
  async startExtension(dataPath, extensionVersion, port = 5540) {
3504
- // Set the bridge mode
3505
2889
  this.bridgeMode = 'bridge';
3506
- // Set the first port to use
3507
2890
  this.port = port;
3508
- // Set Matterbridge logger
3509
- this.log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: "info" /* LogLevel.INFO */ });
2891
+ this.log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4, logLevel: "info" });
3510
2892
  this.log.debug('Matterbridge extension is starting...');
3511
- // Initialize NodeStorage
3512
2893
  this.matterbridgeDirectory = dataPath;
3513
2894
  this.log.debug('Creating node storage manager dir: ' + path.join(this.matterbridgeDirectory, 'node_storage'));
3514
2895
  this.nodeStorage = new NodeStorageManager({ dir: path.join(this.matterbridgeDirectory, 'node_storage'), logging: false });
@@ -3527,13 +2908,10 @@ export class Matterbridge extends EventEmitter {
3527
2908
  };
3528
2909
  this.plugins.set(plugin);
3529
2910
  this.plugins.saveToStorage();
3530
- // Log system info and create .matterbridge directory
3531
2911
  await this.logNodeAndSystemInfo();
3532
2912
  this.matterbridgeDirectory = dataPath;
3533
- // Set matter.js logger level and format
3534
2913
  Logger.defaultLogLevel = MatterLogLevel.INFO;
3535
2914
  Logger.format = MatterLogFormat.ANSI;
3536
- // Start the storage and create matterbridgeContext
3537
2915
  await this.startMatterStorage('json', path.join(this.matterbridgeDirectory, this.matterStorageName));
3538
2916
  if (!this.storageManager)
3539
2917
  return false;
@@ -3543,7 +2921,7 @@ export class Matterbridge extends EventEmitter {
3543
2921
  await this.matterbridgeContext.set('softwareVersion', 1);
3544
2922
  await this.matterbridgeContext.set('softwareVersionString', this.matterbridgeVersion);
3545
2923
  await this.matterbridgeContext.set('hardwareVersion', 1);
3546
- await this.matterbridgeContext.set('hardwareVersionString', extensionVersion); // Update with the extension version
2924
+ await this.matterbridgeContext.set('hardwareVersionString', extensionVersion);
3547
2925
  this.matterServer = this.createMatterServer(this.storageManager);
3548
2926
  this.log.debug(`Creating commissioning server for ${plg}Matterbridge${db}`);
3549
2927
  this.commissioningServer = await this.createCommisioningServer(this.matterbridgeContext, 'Matterbridge');
@@ -3556,7 +2934,6 @@ export class Matterbridge extends EventEmitter {
3556
2934
  await this.startMatterServer();
3557
2935
  this.log.info('Matter server started');
3558
2936
  await this.showCommissioningQRCode(this.commissioningServer, this.matterbridgeContext, this.nodeContext, 'Matterbridge');
3559
- // Set reachability to true and trigger event after 60 seconds
3560
2937
  setTimeout(() => {
3561
2938
  this.log.info(`Setting reachability to true for ${plg}Matterbridge${db}`);
3562
2939
  if (this.commissioningServer)
@@ -3566,31 +2943,14 @@ export class Matterbridge extends EventEmitter {
3566
2943
  }, 60 * 1000);
3567
2944
  return this.commissioningServer.isCommissioned();
3568
2945
  }
3569
- /**
3570
- * Close the Matterbridge instance as extension for zigbee2mqtt.
3571
- * @deprecated This method is deprecated and will be removed in a future version.
3572
- *
3573
- * @returns A Promise that resolves when the initialization is complete.
3574
- */
3575
2946
  async stopExtension() {
3576
- // Closing matter
3577
2947
  await this.stopMatterServer();
3578
- // Clearing the session manager
3579
- // this.matterbridgeContext?.createContext('SessionManager').clear();
3580
- // Closing storage
3581
2948
  await this.stopMatterStorage();
3582
2949
  this.log.info('Matter server stopped');
3583
2950
  }
3584
- /**
3585
- * Checks if the extension is commissioned.
3586
- * @deprecated This method is deprecated and will be removed in a future version.
3587
- *
3588
- * @returns {boolean} Returns true if the extension is commissioned, false otherwise.
3589
- */
3590
2951
  isExtensionCommissioned() {
3591
2952
  if (!this.commissioningServer)
3592
2953
  return false;
3593
2954
  return this.commissioningServer.isCommissioned();
3594
2955
  }
3595
2956
  }
3596
- //# sourceMappingURL=matterbridge.js.map