matterbridge 1.6.5 → 1.6.6-dev.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/README-DEV.md +3 -3
  3. package/README.md +4 -0
  4. package/dist/cli.js +0 -26
  5. package/dist/cluster/export.js +0 -2
  6. package/dist/defaultConfigSchema.js +0 -23
  7. package/dist/deviceManager.js +1 -26
  8. package/dist/index.js +0 -30
  9. package/dist/logger/export.js +0 -1
  10. package/dist/matter/export.js +0 -1
  11. package/dist/matterbridge.js +106 -706
  12. package/dist/matterbridgeAccessoryPlatform.js +0 -33
  13. package/dist/matterbridgeBehaviors.js +10 -29
  14. package/dist/matterbridgeDevice.js +58 -939
  15. package/dist/matterbridgeDeviceTypes.js +21 -42
  16. package/dist/matterbridgeDynamicPlatform.js +0 -33
  17. package/dist/matterbridgeEdge.js +0 -528
  18. package/dist/matterbridgeEndpoint.js +79 -1090
  19. package/dist/matterbridgePlatform.js +36 -76
  20. package/dist/matterbridgeTypes.js +0 -24
  21. package/dist/matterbridgeWebsocket.js +8 -45
  22. package/dist/pluginManager.js +3 -237
  23. package/dist/storage/export.js +0 -1
  24. package/dist/utils/colorUtils.js +33 -165
  25. package/dist/utils/export.js +0 -1
  26. package/dist/utils/utils.js +7 -252
  27. package/frontend/build/asset-manifest.json +3 -3
  28. package/frontend/build/index.html +1 -1
  29. package/frontend/build/static/js/{main.0ab89802.js → main.a742de4e.js} +9 -9
  30. package/frontend/build/static/js/{main.0ab89802.js.map → main.a742de4e.js.map} +1 -1
  31. package/npm-shrinkwrap.json +115 -104
  32. package/package.json +5 -5
  33. package/dist/cli.d.ts +0 -25
  34. package/dist/cli.d.ts.map +0 -1
  35. package/dist/cli.js.map +0 -1
  36. package/dist/cluster/export.d.ts +0 -2
  37. package/dist/cluster/export.d.ts.map +0 -1
  38. package/dist/cluster/export.js.map +0 -1
  39. package/dist/defaultConfigSchema.d.ts +0 -27
  40. package/dist/defaultConfigSchema.d.ts.map +0 -1
  41. package/dist/defaultConfigSchema.js.map +0 -1
  42. package/dist/deviceManager.d.ts +0 -46
  43. package/dist/deviceManager.d.ts.map +0 -1
  44. package/dist/deviceManager.js.map +0 -1
  45. package/dist/index.d.ts +0 -40
  46. package/dist/index.d.ts.map +0 -1
  47. package/dist/index.js.map +0 -1
  48. package/dist/logger/export.d.ts +0 -2
  49. package/dist/logger/export.d.ts.map +0 -1
  50. package/dist/logger/export.js.map +0 -1
  51. package/dist/matter/export.d.ts +0 -5
  52. package/dist/matter/export.d.ts.map +0 -1
  53. package/dist/matter/export.js.map +0 -1
  54. package/dist/matterbridge.d.ts +0 -466
  55. package/dist/matterbridge.d.ts.map +0 -1
  56. package/dist/matterbridge.js.map +0 -1
  57. package/dist/matterbridgeAccessoryPlatform.d.ts +0 -39
  58. package/dist/matterbridgeAccessoryPlatform.d.ts.map +0 -1
  59. package/dist/matterbridgeAccessoryPlatform.js.map +0 -1
  60. package/dist/matterbridgeBehaviors.d.ts +0 -934
  61. package/dist/matterbridgeBehaviors.d.ts.map +0 -1
  62. package/dist/matterbridgeBehaviors.js.map +0 -1
  63. package/dist/matterbridgeDevice.d.ts +0 -6504
  64. package/dist/matterbridgeDevice.d.ts.map +0 -1
  65. package/dist/matterbridgeDevice.js.map +0 -1
  66. package/dist/matterbridgeDeviceTypes.d.ts +0 -65
  67. package/dist/matterbridgeDeviceTypes.d.ts.map +0 -1
  68. package/dist/matterbridgeDeviceTypes.js.map +0 -1
  69. package/dist/matterbridgeDynamicPlatform.d.ts +0 -39
  70. package/dist/matterbridgeDynamicPlatform.d.ts.map +0 -1
  71. package/dist/matterbridgeDynamicPlatform.js.map +0 -1
  72. package/dist/matterbridgeEdge.d.ts +0 -89
  73. package/dist/matterbridgeEdge.d.ts.map +0 -1
  74. package/dist/matterbridgeEdge.js.map +0 -1
  75. package/dist/matterbridgeEndpoint.d.ts +0 -8529
  76. package/dist/matterbridgeEndpoint.d.ts.map +0 -1
  77. package/dist/matterbridgeEndpoint.js.map +0 -1
  78. package/dist/matterbridgePlatform.d.ts +0 -96
  79. package/dist/matterbridgePlatform.d.ts.map +0 -1
  80. package/dist/matterbridgePlatform.js.map +0 -1
  81. package/dist/matterbridgeTypes.d.ts +0 -147
  82. package/dist/matterbridgeTypes.d.ts.map +0 -1
  83. package/dist/matterbridgeTypes.js.map +0 -1
  84. package/dist/matterbridgeWebsocket.d.ts +0 -49
  85. package/dist/matterbridgeWebsocket.d.ts.map +0 -1
  86. package/dist/matterbridgeWebsocket.js.map +0 -1
  87. package/dist/pluginManager.d.ts +0 -238
  88. package/dist/pluginManager.d.ts.map +0 -1
  89. package/dist/pluginManager.js.map +0 -1
  90. package/dist/storage/export.d.ts +0 -2
  91. package/dist/storage/export.d.ts.map +0 -1
  92. package/dist/storage/export.js.map +0 -1
  93. package/dist/utils/colorUtils.d.ts +0 -61
  94. package/dist/utils/colorUtils.d.ts.map +0 -1
  95. package/dist/utils/colorUtils.js.map +0 -1
  96. package/dist/utils/export.d.ts +0 -3
  97. package/dist/utils/export.d.ts.map +0 -1
  98. package/dist/utils/export.js.map +0 -1
  99. package/dist/utils/utils.d.ts +0 -221
  100. package/dist/utils/utils.d.ts.map +0 -1
  101. package/dist/utils/utils.js.map +0 -1
  102. /package/frontend/build/static/js/{main.0ab89802.js.LICENSE.txt → main.a742de4e.js.LICENSE.txt} +0 -0
@@ -1,26 +1,3 @@
1
- /**
2
- * This file contains the class Matterbridge.
3
- *
4
- * @file matterbridge.ts
5
- * @author Luca Liguori
6
- * @date 2023-12-29
7
- * @version 1.5.2
8
- *
9
- * Copyright 2023, 2024, 2025 Luca Liguori.
10
- *
11
- * Licensed under the Apache License, Version 2.0 (the "License");
12
- * you may not use this file except in compliance with the License.
13
- * You may obtain a copy of the License at
14
- *
15
- * http://www.apache.org/licenses/LICENSE-2.0
16
- *
17
- * Unless required by applicable law or agreed to in writing, software
18
- * distributed under the License is distributed on an "AS IS" BASIS,
19
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20
- * See the License for the specific language governing permissions and
21
- * limitations under the License. *
22
- */
23
- // Node.js modules
24
1
  import { fileURLToPath } from 'url';
25
2
  import { promises as fs } from 'fs';
26
3
  import { exec, spawn } from 'child_process';
@@ -29,35 +6,26 @@ import EventEmitter from 'events';
29
6
  import os from 'os';
30
7
  import path from 'path';
31
8
  import { randomBytes } from 'crypto';
32
- // Package modules
33
9
  import https from 'https';
34
10
  import express from 'express';
35
11
  import WebSocket, { WebSocketServer } from 'ws';
36
- // NodeStorage and AnsiLogger modules
37
12
  import { NodeStorageManager } from 'node-persist-manager';
38
13
  import { AnsiLogger, UNDERLINE, UNDERLINEOFF, YELLOW, db, debugStringify, stringify, BRIGHT, RESET, er, nf, rs, wr, RED, GREEN, zb, CYAN, nt, idn, or, hk, BLUE } from 'node-ansi-logger';
39
- // Matterbridge
40
14
  import { MatterbridgeDevice } from './matterbridgeDevice.js';
41
15
  import { WS_ID_LOG, WS_ID_REFRESH_NEEDED, WS_ID_RESTART_NEEDED, wsMessageHandler } from './matterbridgeWebsocket.js';
42
16
  import { logInterfaces, wait, waiter, createZip, copyDirectory, getParameter, getIntParameter, hasParameter } from './utils/utils.js';
43
17
  import { PluginManager } from './pluginManager.js';
44
18
  import { DeviceManager } from './deviceManager.js';
45
19
  import { MatterbridgeEndpoint } from './matterbridgeEndpoint.js';
46
- // @matter
47
20
  import { DeviceTypeId, Logger, LogLevel as MatterLogLevel, LogFormat as MatterLogFormat, VendorId, StorageManager, EndpointServer } from '@matter/main';
48
21
  import { BasicInformationCluster, BridgedDeviceBasicInformation, BridgedDeviceBasicInformationCluster, FixedLabelCluster, GeneralCommissioning, PowerSourceCluster, SwitchCluster, ThreadNetworkDiagnosticsCluster, UserLabelCluster, } from '@matter/main/clusters';
49
22
  import { getClusterNameById, ManualPairingCodeCodec, QrCodeSchema } from '@matter/main/types';
50
23
  import { StorageBackendDisk, StorageBackendJsonFile } from '@matter/nodejs';
51
- // @project-chip
52
24
  import { CommissioningController, CommissioningServer, MatterServer } from '@project-chip/matter.js';
53
25
  import { Aggregator, DeviceTypes, NodeStateInformation } from '@project-chip/matter.js/device';
54
- // Default colors
55
26
  const plg = '\u001B[38;5;33m';
56
27
  const dev = '\u001B[38;5;79m';
57
28
  const typ = '\u001B[38;5;207m';
58
- /**
59
- * Represents the Matterbridge application.
60
- */
61
29
  export class Matterbridge extends EventEmitter {
62
30
  systemInformation = {
63
31
  interfaceName: '',
@@ -93,13 +61,16 @@ 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,
100
68
  mattermdnsinterface: undefined,
101
69
  matteripv4address: undefined,
102
70
  matteripv6address: undefined,
71
+ matterPort: 5540,
72
+ matterDiscriminator: undefined,
73
+ matterPasscode: undefined,
103
74
  restartRequired: false,
104
75
  refreshRequired: false,
105
76
  };
@@ -129,7 +100,6 @@ export class Matterbridge extends EventEmitter {
129
100
  nodeContext;
130
101
  matterStorageName = 'matterbridge' + (getParameter('profile') ? '.' + getParameter('profile') : '') + '.json';
131
102
  nodeStorageName = 'storage' + (getParameter('profile') ? '.' + getParameter('profile') : '');
132
- // Cleanup
133
103
  hasCleanupStarted = false;
134
104
  initialized = false;
135
105
  execRunningCount = 0;
@@ -141,18 +111,16 @@ export class Matterbridge extends EventEmitter {
141
111
  sigtermHandler;
142
112
  exceptionHandler;
143
113
  rejectionHandler;
144
- // Frontend
145
114
  expressApp;
146
115
  httpServer;
147
116
  httpsServer;
148
117
  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
118
+ mdnsInterface;
119
+ ipv4address;
120
+ ipv6address;
121
+ port = 5540;
122
+ passcode;
123
+ discriminator;
156
124
  storageManager;
157
125
  matterbridgeContext;
158
126
  mattercontrollerContext;
@@ -163,26 +131,13 @@ export class Matterbridge extends EventEmitter {
163
131
  aggregatorVendorId = VendorId(getIntParameter('vendorId') ?? 0xfff1);
164
132
  aggregatorProductId = getIntParameter('productId') ?? 0x8000;
165
133
  static instance;
166
- // We load asyncronously so is private
167
134
  constructor() {
168
135
  super();
169
- // Bind the handler to the instance
170
136
  this.matterbridgeMessageHandler = wsMessageHandler.bind(this);
171
137
  }
172
138
  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
139
  static async loadInstance(initialize = false) {
184
140
  if (!Matterbridge.instance) {
185
- // eslint-disable-next-line no-console
186
141
  if (hasParameter('debug'))
187
142
  console.log(GREEN + 'Creating a new instance of Matterbridge.', initialize ? 'Initializing...' : 'Not initializing...', rs);
188
143
  Matterbridge.instance = new Matterbridge();
@@ -191,11 +146,6 @@ export class Matterbridge extends EventEmitter {
191
146
  }
192
147
  return Matterbridge.instance;
193
148
  }
194
- /**
195
- * Call cleanup().
196
- * @deprecated This method is deprecated and is only used for jest tests.
197
- *
198
- */
199
149
  async destroyInstance() {
200
150
  await this.cleanup('destroying instance...', false);
201
151
  await waiter('destroying instance...', () => {
@@ -203,66 +153,39 @@ export class Matterbridge extends EventEmitter {
203
153
  }, false, 60000, 100, false);
204
154
  await wait(1000, 'Wait for the global node_modules and matterbridge version', false);
205
155
  }
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
156
  async initialize() {
217
- // Set the first port to use for the commissioning server (will be incremented in childbridge mode)
218
- this.port = getIntParameter('port') ?? 5540;
219
- // Set the first passcode to use for the commissioning server (will be incremented in childbridge mode)
220
- this.passcode = getIntParameter('passcode');
221
- // Set the first discriminator to use for the commissioning server (will be incremented in childbridge mode)
222
- 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,44 @@ 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)
203
+ this.port = getIntParameter('port') ?? (await this.nodeContext.get('matterport', 5540)) ?? 5540;
204
+ this.passcode = getIntParameter('passcode') ?? (await this.nodeContext.get('matterpasscode'));
205
+ this.discriminator = getIntParameter('discriminator') ?? (await this.nodeContext.get('matterdiscriminator'));
281
206
  if (hasParameter('logger')) {
282
207
  const level = getParameter('logger');
283
208
  if (level === 'debug') {
284
- this.log.logLevel = "debug" /* LogLevel.DEBUG */;
209
+ this.log.logLevel = "debug";
285
210
  }
286
211
  else if (level === 'info') {
287
- this.log.logLevel = "info" /* LogLevel.INFO */;
212
+ this.log.logLevel = "info";
288
213
  }
289
214
  else if (level === 'notice') {
290
- this.log.logLevel = "notice" /* LogLevel.NOTICE */;
215
+ this.log.logLevel = "notice";
291
216
  }
292
217
  else if (level === 'warn') {
293
- this.log.logLevel = "warn" /* LogLevel.WARN */;
218
+ this.log.logLevel = "warn";
294
219
  }
295
220
  else if (level === 'error') {
296
- this.log.logLevel = "error" /* LogLevel.ERROR */;
221
+ this.log.logLevel = "error";
297
222
  }
298
223
  else if (level === 'fatal') {
299
- this.log.logLevel = "fatal" /* LogLevel.FATAL */;
224
+ this.log.logLevel = "fatal";
300
225
  }
301
226
  else {
302
227
  this.log.warn(`Invalid matterbridge logger level: ${level}. Using default level "info".`);
303
- this.log.logLevel = "info" /* LogLevel.INFO */;
228
+ this.log.logLevel = "info";
304
229
  }
305
230
  }
306
231
  else {
307
- this.log.logLevel = await this.nodeContext.get('matterbridgeLogLevel', "info" /* LogLevel.INFO */);
232
+ this.log.logLevel = await this.nodeContext.get('matterbridgeLogLevel', "info");
308
233
  }
309
234
  MatterbridgeDevice.logLevel = this.log.logLevel;
310
- // Create the file logger for matterbridge (context: matterbridgeFileLog)
311
235
  if (hasParameter('filelogger') || (await this.nodeContext.get('matterbridgeFileLog', false))) {
312
236
  AnsiLogger.setGlobalLogfile(path.join(this.matterbridgeDirectory, this.matterbrideLoggerFile), this.log.logLevel, true);
313
237
  this.matterbridgeInformation.fileLogger = true;
314
238
  }
315
239
  this.log.notice('Matterbridge is starting...');
316
240
  this.log.debug(`Matterbridge logLevel: ${this.log.logLevel} fileLoger: ${this.matterbridgeInformation.fileLogger}.`);
317
- // Set matter.js logger level, format and logger (context: matterLogLevel)
318
241
  if (hasParameter('matterlogger')) {
319
242
  const level = getParameter('matterlogger');
320
243
  if (level === 'debug') {
@@ -345,7 +268,6 @@ export class Matterbridge extends EventEmitter {
345
268
  }
346
269
  Logger.format = MatterLogFormat.ANSI;
347
270
  Logger.setLogger('default', this.createMatterLogger());
348
- // Create the file logger for matter.js (context: matterFileLog)
349
271
  if (hasParameter('matterfilelogger') || (await this.nodeContext.get('matterFileLog', false))) {
350
272
  this.matterbridgeInformation.matterFileLogger = true;
351
273
  Logger.addLogger('matterfilelogger', await this.createMatterFileLogger(path.join(this.matterbridgeDirectory, this.matterLoggerFile), true), {
@@ -354,7 +276,6 @@ export class Matterbridge extends EventEmitter {
354
276
  });
355
277
  }
356
278
  this.log.debug(`Matter logLevel: ${Logger.defaultLogLevel} fileLoger: ${this.matterbridgeInformation.matterFileLogger}.`);
357
- // Set the interface to use for the matter server mdnsInterface
358
279
  if (hasParameter('mdnsinterface')) {
359
280
  this.mdnsInterface = getParameter('mdnsinterface');
360
281
  }
@@ -363,7 +284,6 @@ export class Matterbridge extends EventEmitter {
363
284
  if (this.mdnsInterface === '')
364
285
  this.mdnsInterface = undefined;
365
286
  }
366
- // Set the listeningAddressIpv4 for the matter commissioning server
367
287
  if (hasParameter('ipv4address')) {
368
288
  this.ipv4address = getParameter('ipv4address');
369
289
  }
@@ -372,7 +292,6 @@ export class Matterbridge extends EventEmitter {
372
292
  if (this.ipv4address === '')
373
293
  this.ipv4address = undefined;
374
294
  }
375
- // Set the listeningAddressIpv6 for the matter commissioning server
376
295
  if (hasParameter('ipv6address')) {
377
296
  this.ipv6address = getParameter('ipv6address');
378
297
  }
@@ -381,23 +300,17 @@ export class Matterbridge extends EventEmitter {
381
300
  if (this.ipv6address === '')
382
301
  this.ipv6address = undefined;
383
302
  }
384
- // Initialize PluginManager
385
303
  this.plugins = new PluginManager(this);
386
304
  await this.plugins.loadFromStorage();
387
- // Initialize DeviceManager
388
305
  this.devices = new DeviceManager(this, this.nodeContext);
389
- // Get the plugins from node storage and create the plugins node storage contexts
390
306
  for (const plugin of this.plugins) {
391
307
  const packageJson = await this.plugins.parse(plugin);
392
308
  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
309
  this.log.info(`Error parsing plugin ${plg}${plugin.name}${nf}. Trying to reinstall it from npm.`);
396
310
  try {
397
311
  await this.spawnCommand('npm', ['install', '-g', plugin.name, '--omit=dev', '--verbose']);
398
312
  this.log.info(`Plugin ${plg}${plugin.name}${nf} reinstalled.`);
399
313
  plugin.error = false;
400
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
401
314
  }
402
315
  catch (error) {
403
316
  plugin.error = true;
@@ -414,7 +327,6 @@ export class Matterbridge extends EventEmitter {
414
327
  await plugin.nodeContext.set('description', plugin.description);
415
328
  await plugin.nodeContext.set('author', plugin.author);
416
329
  }
417
- // Log system info and create .matterbridge directory
418
330
  await this.logNodeAndSystemInfo();
419
331
  this.log.notice(`Matterbridge version ${this.matterbridgeVersion} ` +
420
332
  `${hasParameter('bridge') || (!hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'bridge') ? 'mode bridge ' : ''}` +
@@ -422,7 +334,6 @@ export class Matterbridge extends EventEmitter {
422
334
  `${hasParameter('controller') ? 'mode controller ' : ''}` +
423
335
  `${this.restartMode !== '' ? 'restart mode ' + this.restartMode + ' ' : ''}` +
424
336
  `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
337
  const minNodeVersion = 18;
427
338
  const nodeVersion = process.versions.node;
428
339
  const versionMajor = parseInt(nodeVersion.split('.')[0]);
@@ -430,17 +341,10 @@ export class Matterbridge extends EventEmitter {
430
341
  this.log.error(`Node version ${versionMajor} is not supported. Please upgrade to ${minNodeVersion} or above.`);
431
342
  throw new Error(`Node version ${versionMajor} is not supported. Please upgrade to ${minNodeVersion} or above.`);
432
343
  }
433
- // Register process handlers
434
344
  this.registerProcessHandlers();
435
- // Parse command line
436
345
  await this.parseCommandLine();
437
346
  this.initialized = true;
438
347
  }
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
348
  async parseCommandLine() {
445
349
  if (hasParameter('help')) {
446
350
  this.log.info(`\nUsage: matterbridge [options]\n
@@ -548,14 +452,12 @@ export class Matterbridge extends EventEmitter {
548
452
  }
549
453
  if (hasParameter('factoryreset')) {
550
454
  try {
551
- // Delete matter storage file
552
455
  await fs.unlink(path.join(this.matterbridgeDirectory, this.matterStorageName));
553
456
  }
554
457
  catch (err) {
555
458
  this.log.error(`Error deleting storage: ${err}`);
556
459
  }
557
460
  try {
558
- // Delete node storage directory with its subdirectories
559
461
  await fs.rm(path.join(this.matterbridgeDirectory, this.nodeStorageName), { recursive: true });
560
462
  }
561
463
  catch (err) {
@@ -569,7 +471,6 @@ export class Matterbridge extends EventEmitter {
569
471
  this.emit('shutdown');
570
472
  return;
571
473
  }
572
- // Start the matter storage and create the matterbridge context
573
474
  try {
574
475
  await this.startMatterStorage('json', path.join(this.matterbridgeDirectory, this.matterStorageName));
575
476
  }
@@ -604,34 +505,28 @@ export class Matterbridge extends EventEmitter {
604
505
  this.emit('shutdown');
605
506
  return;
606
507
  }
607
- // Initialize frontend
608
508
  if (getIntParameter('frontend') !== 0 || getIntParameter('frontend') === undefined)
609
509
  await this.initializeFrontend(getIntParameter('frontend'));
610
- // Check each 60 minutes the latest versions
611
510
  this.checkUpdateInterval = setInterval(() => {
612
511
  this.getMatterbridgeLatestVersion();
613
512
  for (const plugin of this.plugins) {
614
513
  this.getPluginLatestVersion(plugin);
615
514
  }
616
515
  }, 60 * 60 * 1000);
617
- // Start the matterbridge in mode test
618
516
  if (hasParameter('test')) {
619
517
  this.bridgeMode = 'bridge';
620
518
  MatterbridgeDevice.bridgeMode = 'bridge';
621
519
  return;
622
520
  }
623
- // Start the matterbridge in mode controller
624
521
  if (hasParameter('controller')) {
625
522
  this.bridgeMode = 'controller';
626
523
  await this.startController();
627
524
  return;
628
525
  }
629
- // Check if the bridge mode is set and start matterbridge in bridge mode if not set
630
526
  if (!hasParameter('bridge') && !hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === '') {
631
527
  this.log.info('Setting default matterbridge start mode to bridge');
632
528
  await this.nodeContext?.set('bridgeMode', 'bridge');
633
529
  }
634
- // Start matterbridge in bridge mode
635
530
  if (hasParameter('bridge') || (!hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'bridge')) {
636
531
  this.bridgeMode = 'bridge';
637
532
  MatterbridgeDevice.bridgeMode = 'bridge';
@@ -640,7 +535,6 @@ export class Matterbridge extends EventEmitter {
640
535
  await this.startBridge();
641
536
  return;
642
537
  }
643
- // Start matterbridge in childbridge mode
644
538
  if (hasParameter('childbridge') || (!hasParameter('bridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'childbridge')) {
645
539
  this.bridgeMode = 'childbridge';
646
540
  MatterbridgeDevice.bridgeMode = 'childbridge';
@@ -650,28 +544,17 @@ export class Matterbridge extends EventEmitter {
650
544
  return;
651
545
  }
652
546
  }
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
547
  async startPlugins() {
662
- // Check, load and start the plugins
663
548
  for (const plugin of this.plugins) {
664
549
  plugin.configJson = await this.plugins.loadConfig(plugin);
665
550
  plugin.schemaJson = await this.plugins.loadSchema(plugin);
666
- // Check if the plugin is available
667
551
  if (!(await this.plugins.resolve(plugin.path))) {
668
552
  this.log.error(`Plugin ${plg}${plugin.name}${er} not found or not validated. Disabling it.`);
669
553
  plugin.enabled = false;
670
554
  plugin.error = true;
671
555
  continue;
672
556
  }
673
- // Check if the plugin has a new version
674
- this.getPluginLatestVersion(plugin); // No await do it asyncronously
557
+ this.getPluginLatestVersion(plugin);
675
558
  if (!plugin.enabled) {
676
559
  this.log.info(`Plugin ${plg}${plugin.name}${nf} not enabled`);
677
560
  continue;
@@ -686,26 +569,20 @@ export class Matterbridge extends EventEmitter {
686
569
  plugin.addedDevices = undefined;
687
570
  plugin.qrPairingCode = undefined;
688
571
  plugin.manualPairingCode = undefined;
689
- this.plugins.load(plugin, true, 'Matterbridge is starting'); // No await do it asyncronously
572
+ this.plugins.load(plugin, true, 'Matterbridge is starting');
690
573
  }
691
574
  this.wssSendRefreshRequired();
692
575
  }
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
576
  registerProcessHandlers() {
698
577
  this.log.debug(`Registering uncaughtException and unhandledRejection handlers...`);
699
578
  process.removeAllListeners('uncaughtException');
700
579
  process.removeAllListeners('unhandledRejection');
701
580
  this.exceptionHandler = async (error) => {
702
581
  this.log.fatal('Unhandled Exception detected at:', error.stack || error, rs);
703
- // await this.cleanup('Unhandled Exception detected, cleaning up...');
704
582
  };
705
583
  process.on('uncaughtException', this.exceptionHandler);
706
584
  this.rejectionHandler = async (reason, promise) => {
707
585
  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
586
  };
710
587
  process.on('unhandledRejection', this.rejectionHandler);
711
588
  this.log.debug(`Registering SIGINT and SIGTERM signal handlers...`);
@@ -718,9 +595,6 @@ export class Matterbridge extends EventEmitter {
718
595
  };
719
596
  process.on('SIGTERM', this.sigtermHandler);
720
597
  }
721
- /**
722
- * Deregisters the process uncaughtException, unhandledRejection, SIGINT and SIGTERM signal handlers.
723
- */
724
598
  deregisterProcesslHandlers() {
725
599
  this.log.debug(`Deregistering uncaughtException and unhandledRejection handlers...`);
726
600
  if (this.exceptionHandler)
@@ -737,11 +611,7 @@ export class Matterbridge extends EventEmitter {
737
611
  process.off('SIGTERM', this.sigtermHandler);
738
612
  this.sigtermHandler = undefined;
739
613
  }
740
- /**
741
- * Logs the node and system information.
742
- */
743
614
  async logNodeAndSystemInfo() {
744
- // IP address information
745
615
  const networkInterfaces = os.networkInterfaces();
746
616
  this.systemInformation.ipv4Address = '';
747
617
  this.systemInformation.ipv6Address = '';
@@ -761,7 +631,7 @@ export class Matterbridge extends EventEmitter {
761
631
  this.systemInformation.macAddress = detail.mac;
762
632
  }
763
633
  }
764
- if (this.systemInformation.ipv4Address !== '' /* && this.systemInformation.ipv6Address !== ''*/) {
634
+ if (this.systemInformation.ipv4Address !== '') {
765
635
  this.log.debug(`Using interface: '${this.systemInformation.interfaceName}'`);
766
636
  this.log.debug(`- with MAC address: '${this.systemInformation.macAddress}'`);
767
637
  this.log.debug(`- with IPv4 address: '${this.systemInformation.ipv4Address}'`);
@@ -769,22 +639,19 @@ export class Matterbridge extends EventEmitter {
769
639
  break;
770
640
  }
771
641
  }
772
- // Node information
773
642
  this.systemInformation.nodeVersion = process.versions.node;
774
643
  const versionMajor = parseInt(this.systemInformation.nodeVersion.split('.')[0]);
775
644
  const versionMinor = parseInt(this.systemInformation.nodeVersion.split('.')[1]);
776
645
  const versionPatch = parseInt(this.systemInformation.nodeVersion.split('.')[2]);
777
- // Host system information
778
646
  this.systemInformation.hostname = os.hostname();
779
647
  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
648
+ this.systemInformation.osType = os.type();
649
+ this.systemInformation.osRelease = os.release();
650
+ this.systemInformation.osPlatform = os.platform();
651
+ this.systemInformation.osArch = os.arch();
652
+ this.systemInformation.totalMemory = (os.totalmem() / 1024 / 1024 / 1024).toFixed(2) + ' GB';
653
+ this.systemInformation.freeMemory = (os.freemem() / 1024 / 1024 / 1024).toFixed(2) + ' GB';
654
+ this.systemInformation.systemUptime = (os.uptime() / 60 / 60).toFixed(2) + ' hours';
788
655
  this.log.debug('Host System Information:');
789
656
  this.log.debug(`- Hostname: ${this.systemInformation.hostname}`);
790
657
  this.log.debug(`- User: ${this.systemInformation.user}`);
@@ -800,19 +667,15 @@ export class Matterbridge extends EventEmitter {
800
667
  this.log.debug(`- Total Memory: ${this.systemInformation.totalMemory}`);
801
668
  this.log.debug(`- Free Memory: ${this.systemInformation.freeMemory}`);
802
669
  this.log.debug(`- System Uptime: ${this.systemInformation.systemUptime}`);
803
- // Home directory
804
670
  this.homeDirectory = getParameter('homedir') ?? os.homedir();
805
671
  this.matterbridgeInformation.homeDirectory = this.homeDirectory;
806
672
  this.log.debug(`Home Directory: ${this.homeDirectory}`);
807
- // Package root directory
808
673
  const currentFileDirectory = path.dirname(fileURLToPath(import.meta.url));
809
674
  this.rootDirectory = path.resolve(currentFileDirectory, '../');
810
675
  this.matterbridgeInformation.rootDirectory = this.rootDirectory;
811
676
  this.log.debug(`Root Directory: ${this.rootDirectory}`);
812
- // Global node_modules directory
813
677
  if (this.nodeContext)
814
678
  this.globalModulesDirectory = await this.nodeContext.get('globalModulesDirectory', '');
815
- // First run of Matterbridge so the node storage is empty
816
679
  if (this.globalModulesDirectory === '') {
817
680
  try {
818
681
  this.globalModulesDirectory = await this.getGlobalNodeModules();
@@ -836,7 +699,6 @@ export class Matterbridge extends EventEmitter {
836
699
  this.log.error(`Error getting global node_modules directory: ${error}`);
837
700
  });
838
701
  }
839
- // Create the data directory .matterbridge in the home directory
840
702
  this.matterbridgeDirectory = path.join(this.homeDirectory, '.matterbridge');
841
703
  this.matterbridgeInformation.matterbridgeDirectory = this.matterbridgeDirectory;
842
704
  try {
@@ -860,7 +722,6 @@ export class Matterbridge extends EventEmitter {
860
722
  }
861
723
  }
862
724
  this.log.debug(`Matterbridge Directory: ${this.matterbridgeDirectory}`);
863
- // Create the plugin directory Matterbridge in the home directory
864
725
  this.matterbridgePluginDirectory = path.join(this.homeDirectory, 'Matterbridge');
865
726
  this.matterbridgeInformation.matterbridgePluginDirectory = this.matterbridgePluginDirectory;
866
727
  try {
@@ -884,28 +745,19 @@ export class Matterbridge extends EventEmitter {
884
745
  }
885
746
  }
886
747
  this.log.debug(`Matterbridge Plugin Directory: ${this.matterbridgePluginDirectory}`);
887
- // Matterbridge version
888
748
  const packageJson = JSON.parse(await fs.readFile(path.join(this.rootDirectory, 'package.json'), 'utf-8'));
889
749
  this.matterbridgeVersion = packageJson.version;
890
750
  this.matterbridgeInformation.matterbridgeVersion = this.matterbridgeVersion;
891
751
  this.log.debug(`Matterbridge Version: ${this.matterbridgeVersion}`);
892
- // Matterbridge latest version
893
752
  if (this.nodeContext)
894
753
  this.matterbridgeLatestVersion = await this.nodeContext.get('matterbridgeLatestVersion', '');
895
754
  this.log.debug(`Matterbridge Latest Version: ${this.matterbridgeLatestVersion}`);
896
755
  this.getMatterbridgeLatestVersion();
897
- // Current working directory
898
756
  const currentDir = process.cwd();
899
757
  this.log.debug(`Current Working Directory: ${currentDir}`);
900
- // Command line arguments (excluding 'node' and the script name)
901
758
  const cmdArgs = process.argv.slice(2).join(' ');
902
759
  this.log.debug(`Command Line Arguments: ${cmdArgs}`);
903
760
  }
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
761
  async getLatestVersion(packageName) {
910
762
  return new Promise((resolve, reject) => {
911
763
  this.execRunningCount++;
@@ -920,10 +772,6 @@ export class Matterbridge extends EventEmitter {
920
772
  });
921
773
  });
922
774
  }
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
775
  async getGlobalNodeModules() {
928
776
  return new Promise((resolve, reject) => {
929
777
  this.execRunningCount++;
@@ -938,11 +786,6 @@ export class Matterbridge extends EventEmitter {
938
786
  });
939
787
  });
940
788
  }
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
789
  async getMatterbridgeLatestVersion() {
947
790
  this.getLatestVersion('matterbridge')
948
791
  .then(async (matterbridgeLatestVersion) => {
@@ -959,19 +802,8 @@ export class Matterbridge extends EventEmitter {
959
802
  })
960
803
  .catch((error) => {
961
804
  this.log.error(`Error getting Matterbridge latest version: ${error.message}`);
962
- // error.stack && this.log.debug(error.stack);
963
805
  });
964
806
  }
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
807
  async getPluginLatestVersion(plugin) {
976
808
  this.getLatestVersion(plugin.name)
977
809
  .then(async (latestVersion) => {
@@ -983,54 +815,40 @@ export class Matterbridge extends EventEmitter {
983
815
  })
984
816
  .catch((error) => {
985
817
  this.log.error(`Error getting ${plg}${plugin.name}${er} latest version: ${error.message}`);
986
- // error.stack && this.log.debug(error.stack);
987
818
  });
988
819
  }
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
820
  createMatterLogger() {
995
- const matterLogger = new AnsiLogger({ logName: 'Matter', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: "debug" /* LogLevel.DEBUG */ });
821
+ const matterLogger = new AnsiLogger({ logName: 'Matter', logTimestampFormat: 4, logLevel: "debug" });
996
822
  return (_level, formattedLog) => {
997
823
  const logger = formattedLog.slice(44, 44 + 20).trim();
998
824
  const message = formattedLog.slice(65);
999
825
  matterLogger.logName = logger;
1000
826
  switch (_level) {
1001
827
  case MatterLogLevel.DEBUG:
1002
- matterLogger.log("debug" /* LogLevel.DEBUG */, message);
828
+ matterLogger.log("debug", message);
1003
829
  break;
1004
830
  case MatterLogLevel.INFO:
1005
- matterLogger.log("info" /* LogLevel.INFO */, message);
831
+ matterLogger.log("info", message);
1006
832
  break;
1007
833
  case MatterLogLevel.NOTICE:
1008
- matterLogger.log("notice" /* LogLevel.NOTICE */, message);
834
+ matterLogger.log("notice", message);
1009
835
  break;
1010
836
  case MatterLogLevel.WARN:
1011
- matterLogger.log("warn" /* LogLevel.WARN */, message);
837
+ matterLogger.log("warn", message);
1012
838
  break;
1013
839
  case MatterLogLevel.ERROR:
1014
- matterLogger.log("error" /* LogLevel.ERROR */, message);
840
+ matterLogger.log("error", message);
1015
841
  break;
1016
842
  case MatterLogLevel.FATAL:
1017
- matterLogger.log("fatal" /* LogLevel.FATAL */, message);
843
+ matterLogger.log("fatal", message);
1018
844
  break;
1019
845
  default:
1020
- matterLogger.log("debug" /* LogLevel.DEBUG */, message);
846
+ matterLogger.log("debug", message);
1021
847
  break;
1022
848
  }
1023
849
  };
1024
850
  }
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
851
  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
852
  let fileSize = 0;
1035
853
  if (unlink) {
1036
854
  try {
@@ -1079,83 +897,53 @@ export class Matterbridge extends EventEmitter {
1079
897
  }
1080
898
  };
1081
899
  }
1082
- /**
1083
- * Update matterbridge and cleanup.
1084
- */
1085
900
  async updateProcess() {
1086
901
  await this.cleanup('updating...', false);
1087
902
  }
1088
- /**
1089
- * Restarts the process by spawning a new process and exiting the current process.
1090
- */
1091
903
  async restartProcess() {
1092
904
  await this.cleanup('restarting...', true);
1093
905
  }
1094
- /**
1095
- * Shut down the process by exiting the current process.
1096
- */
1097
906
  async shutdownProcess() {
1098
907
  await this.cleanup('shutting down...', false);
1099
908
  }
1100
- /**
1101
- * Shut down the process and reset.
1102
- */
1103
909
  async unregisterAndShutdownProcess() {
1104
910
  this.log.info('Unregistering all devices and shutting down...');
1105
- for (const plugin of this.plugins /* .filter((plugin) => plugin.enabled && !plugin.error))*/) {
911
+ for (const plugin of this.plugins) {
1106
912
  await this.removeAllBridgedDevices(plugin.name);
1107
913
  }
1108
914
  await this.cleanup('unregistered all devices and shutting down...', false);
1109
915
  }
1110
- /**
1111
- * Shut down the process and reset.
1112
- */
1113
916
  async shutdownProcessAndReset() {
1114
917
  await this.cleanup('shutting down with reset...', false);
1115
918
  }
1116
- /**
1117
- * Shut down the process and factory reset.
1118
- */
1119
919
  async shutdownProcessAndFactoryReset() {
1120
920
  await this.cleanup('shutting down with factory reset...', false);
1121
921
  }
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
922
  async cleanup(message, restart = false) {
1129
923
  if (this.initialized && !this.hasCleanupStarted) {
1130
924
  this.hasCleanupStarted = true;
1131
925
  this.log.info(message);
1132
- // Deregisters the process handlers
1133
926
  this.deregisterProcesslHandlers();
1134
- // Clear the start matter interval
1135
927
  if (this.startMatterInterval) {
1136
928
  clearInterval(this.startMatterInterval);
1137
929
  this.startMatterInterval = undefined;
1138
930
  this.log.debug('Start matter interval cleared');
1139
931
  }
1140
- // Clear the check update interval
1141
932
  if (this.checkUpdateInterval) {
1142
933
  clearInterval(this.checkUpdateInterval);
1143
934
  this.checkUpdateInterval = undefined;
1144
935
  this.log.debug('Check update interval cleared');
1145
936
  }
1146
- // Clear the configure timeout
1147
937
  if (this.configureTimeout) {
1148
938
  clearTimeout(this.configureTimeout);
1149
939
  this.configureTimeout = undefined;
1150
940
  this.log.debug('Matterbridge configure timeout cleared');
1151
941
  }
1152
- // Clear the reachability timeout
1153
942
  if (this.reachabilityTimeout) {
1154
943
  clearTimeout(this.reachabilityTimeout);
1155
944
  this.reachabilityTimeout = undefined;
1156
945
  this.log.debug('Matterbridge reachability timeout cleared');
1157
946
  }
1158
- // Calling the shutdown method of each plugin and clear the reachability timeout
1159
947
  for (const plugin of this.plugins) {
1160
948
  if (!plugin.enabled || plugin.error)
1161
949
  continue;
@@ -1166,29 +954,24 @@ export class Matterbridge extends EventEmitter {
1166
954
  this.log.debug(`Plugin ${plg}${plugin.name}${db} reachability timeout cleared`);
1167
955
  }
1168
956
  }
1169
- // Close the http server
1170
957
  if (this.httpServer) {
1171
958
  this.httpServer.close();
1172
959
  this.httpServer.removeAllListeners();
1173
960
  this.httpServer = undefined;
1174
961
  this.log.debug('Frontend http server closed successfully');
1175
962
  }
1176
- // Close the https server
1177
963
  if (this.httpsServer) {
1178
964
  this.httpsServer.close();
1179
965
  this.httpsServer.removeAllListeners();
1180
966
  this.httpsServer = undefined;
1181
967
  this.log.debug('Frontend https server closed successfully');
1182
968
  }
1183
- // Remove listeners from the express app
1184
969
  if (this.expressApp) {
1185
970
  this.expressApp.removeAllListeners();
1186
971
  this.expressApp = undefined;
1187
972
  this.log.debug('Frontend app closed successfully');
1188
973
  }
1189
- // Close the WebSocket server
1190
974
  if (this.webSocketServer) {
1191
- // Close all active connections
1192
975
  this.webSocketServer.clients.forEach((client) => {
1193
976
  if (client.readyState === WebSocket.OPEN) {
1194
977
  client.close();
@@ -1204,35 +987,26 @@ export class Matterbridge extends EventEmitter {
1204
987
  });
1205
988
  this.webSocketServer = undefined;
1206
989
  }
1207
- // Closing matter
1208
990
  await this.stopMatterServer();
1209
- // Closing matter storage
1210
991
  await this.stopMatterStorage();
1211
- // Remove the matterfilelogger
1212
992
  try {
1213
993
  Logger.removeLogger('matterfilelogger');
1214
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1215
994
  }
1216
995
  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
996
  }
1219
- // Serialize registeredDevices
1220
997
  if (this.nodeStorage && this.nodeContext) {
1221
998
  this.log.info('Saving registered devices...');
1222
999
  const serializedRegisteredDevices = [];
1223
1000
  this.devices.forEach(async (device) => {
1224
1001
  const serializedMatterbridgeDevice = device.serialize();
1225
- // this.log.info(`- ${serializedMatterbridgeDevice.deviceName}${rs}\n`, serializedMatterbridgeDevice);
1226
1002
  if (serializedMatterbridgeDevice)
1227
1003
  serializedRegisteredDevices.push(serializedMatterbridgeDevice);
1228
1004
  });
1229
1005
  await this.nodeContext.set('devices', serializedRegisteredDevices);
1230
1006
  this.log.info(`Saved registered devices (${serializedRegisteredDevices?.length})`);
1231
- // Clear nodeContext and nodeStorage (they just need 1000ms to write the data to disk)
1232
1007
  this.log.debug(`Closing node storage context for ${plg}Matterbridge${db}...`);
1233
1008
  await this.nodeContext.close();
1234
1009
  this.nodeContext = undefined;
1235
- // Clear nodeContext for each plugin (they just need 1000ms to write the data to disk)
1236
1010
  for (const plugin of this.plugins) {
1237
1011
  if (plugin.nodeContext) {
1238
1012
  this.log.debug(`Closing node storage context for plugin ${plg}${plugin.name}${db}...`);
@@ -1263,16 +1037,13 @@ export class Matterbridge extends EventEmitter {
1263
1037
  }
1264
1038
  else {
1265
1039
  if (message === 'shutting down with reset...') {
1266
- // Delete matter storage file
1267
1040
  this.log.info('Resetting Matterbridge commissioning information...');
1268
1041
  await fs.unlink(path.join(this.matterbridgeDirectory, this.matterStorageName));
1269
1042
  this.log.info('Reset done! Remove all paired devices from the controllers.');
1270
1043
  }
1271
1044
  if (message === 'shutting down with factory reset...') {
1272
- // Delete matter storage file
1273
1045
  this.log.info('Resetting Matterbridge commissioning information...');
1274
1046
  await fs.unlink(path.join(this.matterbridgeDirectory, this.matterStorageName));
1275
- // Delete node storage directory with its subdirectories
1276
1047
  this.log.info('Resetting Matterbridge storage...');
1277
1048
  await fs.rm(path.join(this.matterbridgeDirectory, this.nodeStorageName), { recursive: true });
1278
1049
  this.log.info('Factory reset done! Remove all paired devices from the controllers.');
@@ -1285,33 +1056,19 @@ export class Matterbridge extends EventEmitter {
1285
1056
  this.initialized = false;
1286
1057
  }
1287
1058
  }
1288
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1289
1059
  async addBridgedEndpoint(pluginName, device) {
1290
- // Nothing to do here
1291
1060
  }
1292
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1293
1061
  async removeBridgedEndpoint(pluginName, device) {
1294
- // Nothing to do here
1295
1062
  }
1296
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1297
1063
  async removeAllBridgedEndpoints(pluginName) {
1298
- // Nothing to do here
1299
1064
  }
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
1065
  async addBridgedDevice(pluginName, device) {
1307
1066
  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
1067
  const plugin = this.plugins.get(pluginName);
1310
1068
  if (!plugin) {
1311
1069
  this.log.error(`Error adding bridged device ${dev}${device.deviceName}${er} (${zb}${device.name}${er}) plugin ${plg}${pluginName}${er} not found`);
1312
1070
  return;
1313
1071
  }
1314
- // Register and add the device to matterbridge aggregator in bridge mode
1315
1072
  if (this.bridgeMode === 'bridge') {
1316
1073
  if (!this.matterAggregator) {
1317
1074
  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 +1076,8 @@ export class Matterbridge extends EventEmitter {
1319
1076
  }
1320
1077
  this.matterAggregator.addBridgedDevice(device);
1321
1078
  }
1322
- // The first time create the commissioning server and the aggregator for DynamicPlatform
1323
- // Register and add the device in childbridge mode
1324
1079
  if (this.bridgeMode === 'childbridge') {
1325
1080
  if (plugin.type === 'AccessoryPlatform') {
1326
- // Check if the plugin is locked with the commissioning server
1327
1081
  if (!plugin.locked) {
1328
1082
  plugin.locked = true;
1329
1083
  plugin.storageContext = await this.importCommissioningServerContext(plugin.name, device);
@@ -1337,7 +1091,6 @@ export class Matterbridge extends EventEmitter {
1337
1091
  }
1338
1092
  }
1339
1093
  if (plugin.type === 'DynamicPlatform') {
1340
- // Check if the plugin is locked with the commissioning server and the aggregator
1341
1094
  if (!plugin.locked) {
1342
1095
  plugin.locked = true;
1343
1096
  this.log.debug(`Creating commissioning server context for ${plg}${plugin.name}${db}`);
@@ -1345,7 +1098,7 @@ export class Matterbridge extends EventEmitter {
1345
1098
  this.log.debug(`Creating commissioning server for ${plg}${plugin.name}${db}`);
1346
1099
  plugin.commissioningServer = await this.createCommisioningServer(plugin.storageContext, plugin.name);
1347
1100
  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
1101
+ plugin.aggregator = await this.createMatterAggregator(plugin.storageContext, plugin.name);
1349
1102
  this.log.debug(`Adding matter aggregator to commissioning server for plugin ${plg}${plugin.name}${db}`);
1350
1103
  plugin.commissioningServer.addDevice(plugin.aggregator);
1351
1104
  this.log.debug(`Adding commissioning server to matter server for plugin ${plg}${plugin.name}${db}`);
@@ -1358,25 +1111,16 @@ export class Matterbridge extends EventEmitter {
1358
1111
  plugin.registeredDevices++;
1359
1112
  if (plugin.addedDevices !== undefined)
1360
1113
  plugin.addedDevices++;
1361
- // Add the device to the DeviceManager
1362
1114
  this.devices.set(device);
1363
1115
  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
1116
  }
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
1117
  async removeBridgedDevice(pluginName, device) {
1372
1118
  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
1119
  const plugin = this.plugins.get(pluginName);
1375
1120
  if (!plugin) {
1376
1121
  this.log.error(`Error removing bridged device ${dev}${device.deviceName}${er} (${zb}${device.name}${er}) for plugin ${plg}${pluginName}${er}: plugin not found`);
1377
1122
  return;
1378
1123
  }
1379
- // Remove the device from matterbridge aggregator in bridge mode
1380
1124
  if (this.bridgeMode === 'bridge') {
1381
1125
  if (!this.matterAggregator) {
1382
1126
  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 +1130,6 @@ export class Matterbridge extends EventEmitter {
1386
1130
  device.setBridgedDeviceReachability(false);
1387
1131
  device.getClusterServerById(BridgedDeviceBasicInformation.Cluster.id)?.triggerReachableChangedEvent({ reachableNewValue: false });
1388
1132
  }
1389
- // device.getClusterServerById(BridgedDeviceBasicInformation.Cluster.id)?.triggerShutDownEvent({});
1390
- // device.getClusterServerById(BridgedDeviceBasicInformation.Cluster.id)?.triggerLeaveEvent({});
1391
1133
  this.matterAggregator?.removeBridgedDevice(device);
1392
1134
  this.log.info(`Removed bridged device(${plugin.registeredDevices}/${plugin.addedDevices}) ${dev}${device.deviceName}${nf} (${zb}${device.name}${nf}) for plugin ${plg}${pluginName}${nf}`);
1393
1135
  if (plugin.registeredDevices !== undefined)
@@ -1395,7 +1137,6 @@ export class Matterbridge extends EventEmitter {
1395
1137
  if (plugin.addedDevices !== undefined)
1396
1138
  plugin.addedDevices--;
1397
1139
  }
1398
- // Remove the device in childbridge mode
1399
1140
  if (this.bridgeMode === 'childbridge') {
1400
1141
  if (plugin.type === 'AccessoryPlatform') {
1401
1142
  if (!plugin.commissioningServer) {
@@ -1419,22 +1160,14 @@ export class Matterbridge extends EventEmitter {
1419
1160
  plugin.registeredDevices--;
1420
1161
  if (plugin.addedDevices !== undefined)
1421
1162
  plugin.addedDevices--;
1422
- // Remove the commissioning server
1423
1163
  if (plugin.registeredDevices === 0 && plugin.addedDevices === 0 && plugin.commissioningServer) {
1424
1164
  this.matterServer?.removeCommissioningServer(plugin.commissioningServer);
1425
1165
  plugin.commissioningServer = undefined;
1426
1166
  this.log.info(`Removed commissioning server for plugin ${plg}${pluginName}${nf}`);
1427
1167
  }
1428
1168
  }
1429
- // Remove the device from the DeviceManager
1430
1169
  this.devices.remove(device);
1431
1170
  }
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
1171
  async removeAllBridgedDevices(pluginName) {
1439
1172
  this.log.debug(`Removing all bridged devices for plugin ${plg}${pluginName}${db}`);
1440
1173
  this.devices.forEach(async (device) => {
@@ -1443,13 +1176,7 @@ export class Matterbridge extends EventEmitter {
1443
1176
  }
1444
1177
  });
1445
1178
  }
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
1179
  async startBridge() {
1452
- // Plugins are configured by a timer when matter server is started and plugin.configured is set to true
1453
1180
  if (!this.storageManager)
1454
1181
  throw new Error('No storage manager initialized');
1455
1182
  if (!this.matterbridgeContext)
@@ -1468,7 +1195,6 @@ export class Matterbridge extends EventEmitter {
1468
1195
  let failCount = 0;
1469
1196
  this.startMatterInterval = setInterval(async () => {
1470
1197
  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
1198
  if (!plugin.enabled)
1473
1199
  continue;
1474
1200
  if (plugin.error) {
@@ -1493,18 +1219,15 @@ export class Matterbridge extends EventEmitter {
1493
1219
  clearInterval(this.startMatterInterval);
1494
1220
  this.startMatterInterval = undefined;
1495
1221
  this.log.debug('Cleared startMatterInterval interval for Matterbridge');
1496
- // Start the Matter server
1497
1222
  await this.startMatterServer();
1498
1223
  this.log.notice('Matter server started');
1499
- // Show the QR code for commissioning or log the already commissioned message
1500
1224
  await this.showCommissioningQRCode(this.commissioningServer, this.matterbridgeContext, this.nodeContext, 'Matterbridge');
1501
- // Configure the plugins
1502
1225
  this.configureTimeout = setTimeout(async () => {
1503
1226
  for (const plugin of this.plugins) {
1504
1227
  if (!plugin.enabled || !plugin.loaded || !plugin.started || plugin.error)
1505
1228
  continue;
1506
1229
  try {
1507
- await this.plugins.configure(plugin); // TODO No await do it in parallel
1230
+ await this.plugins.configure(plugin);
1508
1231
  }
1509
1232
  catch (error) {
1510
1233
  plugin.error = true;
@@ -1513,7 +1236,6 @@ export class Matterbridge extends EventEmitter {
1513
1236
  }
1514
1237
  this.wssSendRefreshRequired();
1515
1238
  }, 30 * 1000);
1516
- // Setting reachability to true
1517
1239
  this.reachabilityTimeout = setTimeout(() => {
1518
1240
  this.log.info(`Setting reachability to true for ${plg}Matterbridge${db}`);
1519
1241
  if (this.commissioningServer)
@@ -1523,14 +1245,7 @@ export class Matterbridge extends EventEmitter {
1523
1245
  }, 60 * 1000);
1524
1246
  }, 1000);
1525
1247
  }
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
1248
  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
1249
  if (!this.storageManager)
1535
1250
  throw new Error('No storage manager initialized');
1536
1251
  this.matterServer = this.createMatterServer(this.storageManager);
@@ -1540,7 +1255,6 @@ export class Matterbridge extends EventEmitter {
1540
1255
  this.startMatterInterval = setInterval(async () => {
1541
1256
  let allStarted = true;
1542
1257
  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
1258
  if (!plugin.enabled)
1545
1259
  continue;
1546
1260
  if (plugin.error) {
@@ -1568,16 +1282,14 @@ export class Matterbridge extends EventEmitter {
1568
1282
  clearInterval(this.startMatterInterval);
1569
1283
  this.startMatterInterval = undefined;
1570
1284
  this.log.debug('Cleared startMatterInterval interval in childbridge mode');
1571
- // Start the Matter server
1572
1285
  await this.startMatterServer();
1573
1286
  this.log.notice('Matter server started');
1574
- // Configure the plugins
1575
1287
  this.configureTimeout = setTimeout(async () => {
1576
1288
  for (const plugin of this.plugins) {
1577
1289
  if (!plugin.enabled || !plugin.loaded || !plugin.started || plugin.error)
1578
1290
  continue;
1579
1291
  try {
1580
- await this.plugins.configure(plugin); // TODO No await do it in parallel
1292
+ await this.plugins.configure(plugin);
1581
1293
  }
1582
1294
  catch (error) {
1583
1295
  plugin.error = true;
@@ -1606,7 +1318,6 @@ export class Matterbridge extends EventEmitter {
1606
1318
  continue;
1607
1319
  }
1608
1320
  await this.showCommissioningQRCode(plugin.commissioningServer, plugin.storageContext, plugin.nodeContext, plugin.name);
1609
- // Setting reachability to true
1610
1321
  plugin.reachabilityTimeout = setTimeout(() => {
1611
1322
  this.log.info(`Setting reachability to true for ${plg}${plugin.name}${db}`);
1612
1323
  if (plugin.commissioningServer)
@@ -1619,11 +1330,6 @@ export class Matterbridge extends EventEmitter {
1619
1330
  }
1620
1331
  }, 1000);
1621
1332
  }
1622
- /**
1623
- * Starts the Matterbridge controller.
1624
- * @private
1625
- * @returns {Promise<void>} A promise that resolves when the Matterbridge is started.
1626
- */
1627
1333
  async startController() {
1628
1334
  if (!this.storageManager) {
1629
1335
  this.log.error('No storage manager initialized');
@@ -1686,7 +1392,7 @@ export class Matterbridge extends EventEmitter {
1686
1392
  const nodeId = await this.commissioningController.commissionNode(options);
1687
1393
  this.log.info(`Commissioning successfully done with nodeId: ${nodeId}`);
1688
1394
  this.log.info('ActiveSessionInformation:', this.commissioningController.getActiveSessionInformation());
1689
- } // (hasParameter('pairingcode'))
1395
+ }
1690
1396
  if (hasParameter('unpairall')) {
1691
1397
  this.log.info('***Commissioning controller unpairing all nodes...');
1692
1398
  const nodeIds = this.commissioningController.getCommissionedNodes();
@@ -1697,8 +1403,6 @@ export class Matterbridge extends EventEmitter {
1697
1403
  return;
1698
1404
  }
1699
1405
  if (hasParameter('discover')) {
1700
- // const discover = await this.commissioningController.discoverCommissionableDevices({ productId: 0x8000, deviceType: 0xfff1 });
1701
- // console.log(discover);
1702
1406
  }
1703
1407
  if (!this.commissioningController.isCommissioned()) {
1704
1408
  this.log.info('***Commissioning controller is not commissioned: use matterbridge -controller -pairingcode [pairingcode] to commission a device');
@@ -1739,12 +1443,10 @@ export class Matterbridge extends EventEmitter {
1739
1443
  },
1740
1444
  });
1741
1445
  node.logStructure();
1742
- // Get the interaction client
1743
1446
  this.log.info('Getting the interaction client');
1744
1447
  const interactionClient = await node.getInteractionClient();
1745
1448
  let cluster;
1746
1449
  let attributes;
1747
- // Log BasicInformationCluster
1748
1450
  cluster = BasicInformationCluster;
1749
1451
  attributes = await interactionClient.getMultipleAttributes({
1750
1452
  attributes: [{ clusterId: cluster.id }],
@@ -1754,7 +1456,6 @@ export class Matterbridge extends EventEmitter {
1754
1456
  attributes.forEach((attribute) => {
1755
1457
  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
1458
  });
1757
- // Log PowerSourceCluster
1758
1459
  cluster = PowerSourceCluster;
1759
1460
  attributes = await interactionClient.getMultipleAttributes({
1760
1461
  attributes: [{ clusterId: cluster.id }],
@@ -1764,7 +1465,6 @@ export class Matterbridge extends EventEmitter {
1764
1465
  attributes.forEach((attribute) => {
1765
1466
  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
1467
  });
1767
- // Log ThreadNetworkDiagnostics
1768
1468
  cluster = ThreadNetworkDiagnosticsCluster;
1769
1469
  attributes = await interactionClient.getMultipleAttributes({
1770
1470
  attributes: [{ clusterId: cluster.id }],
@@ -1774,7 +1474,6 @@ export class Matterbridge extends EventEmitter {
1774
1474
  attributes.forEach((attribute) => {
1775
1475
  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
1476
  });
1777
- // Log SwitchCluster
1778
1477
  cluster = SwitchCluster;
1779
1478
  attributes = await interactionClient.getMultipleAttributes({
1780
1479
  attributes: [{ clusterId: cluster.id }],
@@ -1795,15 +1494,6 @@ export class Matterbridge extends EventEmitter {
1795
1494
  this.log.info('Subscribed to all attributes and events');
1796
1495
  }
1797
1496
  }
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
1497
  async startMatterStorage(storageType, storageName) {
1808
1498
  this.log.debug(`Starting matter ${storageType} storage ${CYAN}${storageName}${db}`);
1809
1499
  if (storageType === 'disk') {
@@ -1849,12 +1539,6 @@ export class Matterbridge extends EventEmitter {
1849
1539
  this.log.debug(`Creating commissioning server context for ${plg}Matterbridge${db}`);
1850
1540
  this.matterbridgeContext = await this.createCommissioningServerContext('Matterbridge', 'Matterbridge', DeviceTypes.AGGREGATOR.code, 0xfff1, 'Matterbridge', 0x8000, 'Matterbridge aggregator');
1851
1541
  }
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
1542
  async backupMatterStorage(storageName, backupName) {
1859
1543
  try {
1860
1544
  this.log.debug(`Making backup copy of ${storageName}`);
@@ -1875,12 +1559,6 @@ export class Matterbridge extends EventEmitter {
1875
1559
  }
1876
1560
  }
1877
1561
  }
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
1562
  async restoreMatterStorage(backupName, storageName) {
1885
1563
  try {
1886
1564
  this.log.notice(`Restoring the backup copy of ${storageName}`);
@@ -1901,10 +1579,6 @@ export class Matterbridge extends EventEmitter {
1901
1579
  }
1902
1580
  }
1903
1581
  }
1904
- /**
1905
- * Stops the matter storage.
1906
- * @returns {Promise<void>} A promise that resolves when the storage is stopped.
1907
- */
1908
1582
  async stopMatterStorage() {
1909
1583
  this.log.debug('Stopping storage');
1910
1584
  await this.storageManager?.close();
@@ -1913,14 +1587,8 @@ export class Matterbridge extends EventEmitter {
1913
1587
  this.matterbridgeContext = undefined;
1914
1588
  this.mattercontrollerContext = undefined;
1915
1589
  }
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
1590
  createMatterServer(storageManager) {
1922
1591
  this.log.debug('Creating matter server');
1923
- // Validate mdnsInterface
1924
1592
  if (this.mdnsInterface) {
1925
1593
  const networkInterfaces = os.networkInterfaces();
1926
1594
  const availableInterfaces = Object.keys(networkInterfaces);
@@ -1936,10 +1604,6 @@ export class Matterbridge extends EventEmitter {
1936
1604
  this.log.debug(`Created matter server with mdnsInterface: ${this.mdnsInterface ?? 'all available interfaces'}`);
1937
1605
  return matterServer;
1938
1606
  }
1939
- /**
1940
- * Starts the Matter server.
1941
- * If the Matter server is not initialized, it logs an error and performs cleanup.
1942
- */
1943
1607
  async startMatterServer() {
1944
1608
  if (!this.matterServer) {
1945
1609
  this.log.error('No matter server initialized');
@@ -1949,11 +1613,7 @@ export class Matterbridge extends EventEmitter {
1949
1613
  this.log.debug('Starting matter server...');
1950
1614
  await this.matterServer.start();
1951
1615
  this.log.debug('Started matter server');
1952
- // this.commissioningServer?.getRootEndpoint() && logEndpoint(this.commissioningServer?.getRootEndpoint());
1953
1616
  }
1954
- /**
1955
- * Stops the Matter server, commissioningServer and commissioningController.
1956
- */
1957
1617
  async stopMatterServer() {
1958
1618
  this.log.debug('Stopping matter commissioningServer');
1959
1619
  await this.commissioningServer?.close();
@@ -1967,86 +1627,29 @@ export class Matterbridge extends EventEmitter {
1967
1627
  this.matterAggregator = undefined;
1968
1628
  this.matterServer = undefined;
1969
1629
  }
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
1630
  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
1631
  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
1632
  return matterAggregator;
2022
1633
  }
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
1634
  async createCommisioningServer(context, pluginName) {
2031
1635
  this.log.debug(`Creating matter commissioning server for plugin ${plg}${pluginName}${db}`);
2032
1636
  const deviceName = await context.get('deviceName');
2033
1637
  const deviceType = await context.get('deviceType');
2034
1638
  const vendorId = await context.get('vendorId');
2035
- const vendorName = await context.get('vendorName'); // Home app = Manufacturer
1639
+ const vendorName = await context.get('vendorName');
2036
1640
  const productId = await context.get('productId');
2037
- const productName = await context.get('productName'); // Home app = Model
1641
+ const productName = await context.get('productName');
2038
1642
  const serialNumber = await context.get('serialNumber');
2039
1643
  const uniqueId = await context.get('uniqueId');
2040
1644
  const softwareVersion = await context.get('softwareVersion', 1);
2041
- const softwareVersionString = await context.get('softwareVersionString', '1.0.0'); // Home app = Firmware Revision
1645
+ const softwareVersionString = await context.get('softwareVersionString', '1.0.0');
2042
1646
  const hardwareVersion = await context.get('hardwareVersion', 1);
2043
1647
  const hardwareVersionString = await context.get('hardwareVersionString', '1.0.0');
2044
1648
  this.log.debug(`Creating matter commissioning server for plugin ${plg}${pluginName}${db} with deviceName '${deviceName}' deviceType ${deviceType}(0x${deviceType.toString(16).padStart(4, '0')})`);
2045
1649
  this.log.debug(`Creating matter commissioning server for plugin ${plg}${pluginName}${db} with uniqueId ${uniqueId} serialNumber ${serialNumber}`);
2046
1650
  this.log.debug(`Creating matter commissioning server for plugin ${plg}${pluginName}${db} with softwareVersion ${softwareVersion} softwareVersionString ${softwareVersionString}`);
2047
1651
  this.log.debug(`Creating matter commissioning server for plugin ${plg}${pluginName}${db} with hardwareVersion ${hardwareVersion} hardwareVersionString ${hardwareVersionString}`);
2048
- 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
1652
+ this.log.debug(`Creating matter commissioning server for plugin ${plg}${pluginName}${db} with nodeLabel '${productName}' port ${CYAN}${this.port}${db} discriminator ${CYAN}${this.discriminator}${db} passcode ${CYAN}${this.passcode}${db} `);
2050
1653
  if (this.ipv4address) {
2051
1654
  const networkInterfaces = os.networkInterfaces();
2052
1655
  const availableAddresses = Object.values(networkInterfaces)
@@ -2061,7 +1664,6 @@ export class Matterbridge extends EventEmitter {
2061
1664
  this.log.info(`Using ipv4address '${this.ipv4address}' for the Matter commissioning server.`);
2062
1665
  }
2063
1666
  }
2064
- // Validate ipv6address
2065
1667
  if (this.ipv6address) {
2066
1668
  const networkInterfaces = os.networkInterfaces();
2067
1669
  const availableAddresses = Object.values(networkInterfaces)
@@ -2092,7 +1694,7 @@ export class Matterbridge extends EventEmitter {
2092
1694
  nodeLabel: productName,
2093
1695
  productLabel: productName,
2094
1696
  softwareVersion,
2095
- softwareVersionString, // Home app = Firmware Revision
1697
+ softwareVersionString,
2096
1698
  hardwareVersion,
2097
1699
  hardwareVersionString,
2098
1700
  uniqueId,
@@ -2188,24 +1790,6 @@ export class Matterbridge extends EventEmitter {
2188
1790
  commissioningServer.addCommandHandler('testEventTrigger', async ({ request: { enableKey, eventTrigger } }) => this.log.info(`testEventTrigger called on GeneralDiagnostic cluster: ${enableKey} ${eventTrigger}`));
2189
1791
  return commissioningServer;
2190
1792
  }
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
1793
  async createCommissioningServerContext(pluginName, deviceName, deviceType, vendorId, vendorName, productId, productName) {
2210
1794
  if (!this.storageManager)
2211
1795
  throw new Error('No storage manager initialized');
@@ -2233,13 +1817,6 @@ export class Matterbridge extends EventEmitter {
2233
1817
  this.log.debug(`- hardwareVersion: ${await storageContext.get('hardwareVersion')} hardwareVersionString: ${await storageContext.get('hardwareVersionString')}`);
2234
1818
  return storageContext;
2235
1819
  }
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
1820
  async importCommissioningServerContext(pluginName, device) {
2244
1821
  this.log.debug(`Importing matter commissioning server storage context from device for ${plg}${pluginName}${db}`);
2245
1822
  const basic = device.getClusterServer(BasicInformationCluster);
@@ -2274,14 +1851,6 @@ export class Matterbridge extends EventEmitter {
2274
1851
  this.log.debug(`- hardwareVersion: ${await storageContext.get('hardwareVersion')} hardwareVersionString: ${await storageContext.get('hardwareVersionString')}`);
2275
1852
  return storageContext;
2276
1853
  }
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
1854
  async showCommissioningQRCode(commissioningServer, storageContext, nodeContext, pluginName) {
2286
1855
  if (!commissioningServer || !storageContext || !nodeContext || !pluginName) {
2287
1856
  this.log.error(`showCommissioningQRCode error: commissioningServer: ${!commissioningServer} storageContext: ${!storageContext} nodeContext: ${!nodeContext} pluginName: ${pluginName}`);
@@ -2292,8 +1861,7 @@ export class Matterbridge extends EventEmitter {
2292
1861
  const { qrPairingCode, manualPairingCode } = commissioningServer.getPairingCode();
2293
1862
  const QrCode = new QrCodeSchema();
2294
1863
  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 */)
1864
+ if (this.log.logLevel === "debug" || this.log.logLevel === "info")
2297
1865
  console.log(`${QrCode.encode(qrPairingCode)}\n`);
2298
1866
  this.log.info(`${plg}${pluginName}${nf} \n\nqrPairingCode: ${qrPairingCode} \n\nManual pairing code: ${manualPairingCode}\n`);
2299
1867
  if (pluginName === 'Matterbridge') {
@@ -2340,12 +1908,6 @@ export class Matterbridge extends EventEmitter {
2340
1908
  }
2341
1909
  this.wssSendRefreshRequired();
2342
1910
  }
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
1911
  sanitizeFabricInformations(fabricInfo) {
2350
1912
  return fabricInfo.map((info) => {
2351
1913
  return {
@@ -2359,12 +1921,6 @@ export class Matterbridge extends EventEmitter {
2359
1921
  };
2360
1922
  });
2361
1923
  }
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
1924
  sanitizeSessionInformation(sessionInfo) {
2369
1925
  return sessionInfo
2370
1926
  .filter((session) => session.isPeerActive)
@@ -2392,12 +1948,6 @@ export class Matterbridge extends EventEmitter {
2392
1948
  };
2393
1949
  });
2394
1950
  }
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
1951
  setCommissioningServerReachability(commissioningServer, reachable) {
2402
1952
  const basicInformationCluster = commissioningServer?.getRootClusterServer(BasicInformationCluster);
2403
1953
  if (basicInformationCluster && basicInformationCluster.attributes.reachable !== undefined)
@@ -2405,11 +1955,6 @@ export class Matterbridge extends EventEmitter {
2405
1955
  if (basicInformationCluster && basicInformationCluster.triggerReachableChangedEvent)
2406
1956
  basicInformationCluster.triggerReachableChangedEvent({ reachableNewValue: reachable });
2407
1957
  }
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
1958
  setAggregatorReachability(matterAggregator, reachable) {
2414
1959
  const basicInformationCluster = matterAggregator.getClusterServer(BasicInformationCluster);
2415
1960
  if (basicInformationCluster && basicInformationCluster.attributes.reachable !== undefined)
@@ -2422,12 +1967,6 @@ export class Matterbridge extends EventEmitter {
2422
1967
  device.getClusterServer(BridgedDeviceBasicInformationCluster)?.triggerReachableChangedEvent({ reachableNewValue: reachable });
2423
1968
  });
2424
1969
  }
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
1970
  setDeviceReachability(device, reachable) {
2432
1971
  const basicInformationCluster = device.getClusterServer(BasicInformationCluster);
2433
1972
  if (basicInformationCluster && basicInformationCluster.attributes.reachable !== undefined)
@@ -2476,10 +2015,6 @@ export class Matterbridge extends EventEmitter {
2476
2015
  }
2477
2016
  return vendorName;
2478
2017
  };
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
2018
  async getBaseRegisteredPlugins() {
2484
2019
  const baseRegisteredPlugins = [];
2485
2020
  for (const plugin of this.plugins) {
@@ -2511,36 +2046,13 @@ export class Matterbridge extends EventEmitter {
2511
2046
  }
2512
2047
  return baseRegisteredPlugins;
2513
2048
  }
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
2049
  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
2050
  const cmdLine = command + ' ' + args.join(' ');
2535
2051
  if (process.platform === 'win32' && command === 'npm') {
2536
- // Must be spawn('cmd.exe', ['/c', 'npm -g install <package>']);
2537
2052
  const argstring = 'npm ' + args.join(' ');
2538
2053
  args.splice(0, args.length, '/c', argstring);
2539
2054
  command = 'cmd.exe';
2540
2055
  }
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
2056
  if (hasParameter('sudo') || (process.platform === 'linux' && command === 'npm' && !hasParameter('docker') && !hasParameter('nosudo'))) {
2545
2057
  args.unshift(command);
2546
2058
  command = 'sudo';
@@ -2598,102 +2110,55 @@ export class Matterbridge extends EventEmitter {
2598
2110
  }
2599
2111
  });
2600
2112
  }
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
2113
  wssSendMessage(level, time, name, message) {
2610
2114
  if (!level || !time || !name || !message)
2611
2115
  return;
2612
- // Remove ANSI escape codes from the message
2613
- // eslint-disable-next-line no-control-regex
2614
2116
  message = message.replace(/\x1B\[[0-9;]*[m|s|u|K]/g, '');
2615
- // Remove leading asterisks from the message
2616
2117
  message = message.replace(/^\*+/, '');
2617
- // Replace all occurrences of \t and \n
2618
2118
  message = message.replace(/[\t\n]/g, '');
2619
- // Remove non-printable characters
2620
- // eslint-disable-next-line no-control-regex
2621
2119
  message = message.replace(/[\x00-\x1F\x7F]/g, '');
2622
- // Replace all occurrences of \" with "
2623
2120
  message = message.replace(/\\"/g, '"');
2624
- // Define the maximum allowed length for continuous characters without a space
2625
2121
  const maxContinuousLength = 100;
2626
2122
  const keepStartLength = 20;
2627
2123
  const keepEndLength = 20;
2628
- // Split the message into words
2629
2124
  message = message
2630
2125
  .split(' ')
2631
2126
  .map((word) => {
2632
- // If the word length exceeds the max continuous length, insert spaces and truncate
2633
2127
  if (word.length > maxContinuousLength) {
2634
2128
  return word.slice(0, keepStartLength) + ' ... ' + word.slice(-keepEndLength);
2635
2129
  }
2636
2130
  return word;
2637
2131
  })
2638
2132
  .join(' ');
2639
- // Send the message to all connected clients
2640
2133
  this.webSocketServer?.clients.forEach((client) => {
2641
2134
  if (client.readyState === WebSocket.OPEN) {
2642
2135
  client.send(JSON.stringify({ id: WS_ID_LOG, src: 'Matterbridge', level, time, name, message }));
2643
2136
  }
2644
2137
  });
2645
2138
  }
2646
- /**
2647
- * Sends a need to refresh WebSocket message to all connected clients.
2648
- *
2649
- */
2650
2139
  wssSendRefreshRequired() {
2651
2140
  this.matterbridgeInformation.refreshRequired = true;
2652
- // Send the message to all connected clients
2653
2141
  this.webSocketServer?.clients.forEach((client) => {
2654
2142
  if (client.readyState === WebSocket.OPEN) {
2655
2143
  client.send(JSON.stringify({ id: WS_ID_REFRESH_NEEDED, src: 'Matterbridge', dst: 'Matterbridge', method: 'refresh_required', params: {} }));
2656
2144
  }
2657
2145
  });
2658
2146
  }
2659
- /**
2660
- * Sends a need to restart WebSocket message to all connected clients.
2661
- *
2662
- */
2663
2147
  wssSendRestartRequired() {
2664
2148
  this.matterbridgeInformation.restartRequired = true;
2665
- // Send the message to all connected clients
2666
2149
  this.webSocketServer?.clients.forEach((client) => {
2667
2150
  if (client.readyState === WebSocket.OPEN) {
2668
2151
  client.send(JSON.stringify({ id: WS_ID_RESTART_NEEDED, src: 'Matterbridge', dst: 'Matterbridge', method: 'restart_required', params: {} }));
2669
2152
  }
2670
2153
  });
2671
2154
  }
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
2155
  async initializeFrontend(port = 8283) {
2678
2156
  let initializeError = false;
2679
2157
  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
2158
  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
2159
  this.expressApp.use(express.static(path.join(this.rootDirectory, 'frontend/build')));
2693
2160
  if (!hasParameter('ssl')) {
2694
- // Create an HTTP server and attach the express app
2695
2161
  this.httpServer = createServer(this.expressApp);
2696
- // Listen on the specified port
2697
2162
  if (hasParameter('ingress')) {
2698
2163
  this.httpServer.listen(port, '0.0.0.0', () => {
2699
2164
  this.log.info(`The frontend http server is listening on ${UNDERLINE}http://0.0.0.0:${port}${UNDERLINEOFF}${rs}`);
@@ -2707,7 +2172,6 @@ export class Matterbridge extends EventEmitter {
2707
2172
  this.log.info(`The frontend http server is listening on ${UNDERLINE}http://[${this.systemInformation.ipv6Address}]:${port}${UNDERLINEOFF}${rs}`);
2708
2173
  });
2709
2174
  }
2710
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
2711
2175
  this.httpServer.on('error', (error) => {
2712
2176
  this.log.error(`Frontend http server error listening on ${port}`);
2713
2177
  switch (error.code) {
@@ -2723,7 +2187,6 @@ export class Matterbridge extends EventEmitter {
2723
2187
  });
2724
2188
  }
2725
2189
  else {
2726
- // Load the SSL certificate, the private key and optionally the CA certificate
2727
2190
  let cert;
2728
2191
  try {
2729
2192
  cert = await fs.readFile(path.join(this.matterbridgeDirectory, 'certs/cert.pem'), 'utf8');
@@ -2751,9 +2214,7 @@ export class Matterbridge extends EventEmitter {
2751
2214
  this.log.info(`CA certificate file ${path.join(this.matterbridgeDirectory, 'certs/ca.pem')} not loaded: ${error}`);
2752
2215
  }
2753
2216
  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
2217
  this.httpsServer = https.createServer(serverOptions, this.expressApp);
2756
- // Listen on the specified port
2757
2218
  if (hasParameter('ingress')) {
2758
2219
  this.httpsServer.listen(port, '0.0.0.0', () => {
2759
2220
  this.log.info(`The frontend https server is listening on ${UNDERLINE}https://0.0.0.0:${port}${UNDERLINEOFF}${rs}`);
@@ -2767,7 +2228,6 @@ export class Matterbridge extends EventEmitter {
2767
2228
  this.log.info(`The frontend https server is listening on ${UNDERLINE}https://[${this.systemInformation.ipv6Address}]:${port}${UNDERLINEOFF}${rs}`);
2768
2229
  });
2769
2230
  }
2770
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
2771
2231
  this.httpsServer.on('error', (error) => {
2772
2232
  this.log.error(`Frontend https server error listening on ${port}`);
2773
2233
  switch (error.code) {
@@ -2784,13 +2244,12 @@ export class Matterbridge extends EventEmitter {
2784
2244
  }
2785
2245
  if (initializeError)
2786
2246
  return;
2787
- // Createe a WebSocket server and attach it to the http or https server
2788
2247
  const wssPort = port;
2789
2248
  const wssHost = hasParameter('ssl') ? `wss://${this.systemInformation.ipv4Address}:${wssPort}` : `ws://${this.systemInformation.ipv4Address}:${wssPort}`;
2790
2249
  this.webSocketServer = new WebSocketServer(hasParameter('ssl') ? { server: this.httpsServer } : { server: this.httpServer });
2791
2250
  this.webSocketServer.on('connection', (ws, request) => {
2792
2251
  const clientIp = request.socket.remoteAddress;
2793
- AnsiLogger.setGlobalCallback(this.wssSendMessage.bind(this), "debug" /* LogLevel.DEBUG */);
2252
+ AnsiLogger.setGlobalCallback(this.wssSendMessage.bind(this), "debug");
2794
2253
  this.log.info(`WebSocketServer client "${clientIp}" connected to Matterbridge`);
2795
2254
  ws.on('message', (message) => {
2796
2255
  this.log.debug(`WebSocket client message: ${message}`);
@@ -2823,7 +2282,6 @@ export class Matterbridge extends EventEmitter {
2823
2282
  this.webSocketServer.on('error', (ws, error) => {
2824
2283
  this.log.error(`WebSocketServer error: ${error}`);
2825
2284
  });
2826
- // Endpoint to validate login code
2827
2285
  this.expressApp.post('/api/login', express.json(), async (req, res) => {
2828
2286
  const { password } = req.body;
2829
2287
  this.log.debug('The frontend sent /api/login', password);
@@ -2842,14 +2300,12 @@ export class Matterbridge extends EventEmitter {
2842
2300
  this.log.warn('/api/login error wrong password');
2843
2301
  res.json({ valid: false });
2844
2302
  }
2845
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
2846
2303
  }
2847
2304
  catch (error) {
2848
2305
  this.log.error('/api/login error getting password');
2849
2306
  res.json({ valid: false });
2850
2307
  }
2851
2308
  });
2852
- // Endpoint to provide settings
2853
2309
  this.expressApp.get('/api/settings', express.json(), async (req, res) => {
2854
2310
  this.log.debug('The frontend sent /api/settings');
2855
2311
  this.matterbridgeInformation.bridgeMode = this.bridgeMode;
@@ -2859,6 +2315,9 @@ export class Matterbridge extends EventEmitter {
2859
2315
  this.matterbridgeInformation.mattermdnsinterface = (await this.nodeContext?.get('mattermdnsinterface', '')) || '';
2860
2316
  this.matterbridgeInformation.matteripv4address = (await this.nodeContext?.get('matteripv4address', '')) || '';
2861
2317
  this.matterbridgeInformation.matteripv6address = (await this.nodeContext?.get('matteripv6address', '')) || '';
2318
+ this.matterbridgeInformation.matterPort = (await this.nodeContext?.get('matterport', 5540)) ?? 5540;
2319
+ this.matterbridgeInformation.matterDiscriminator = await this.nodeContext?.get('matterdiscriminator');
2320
+ this.matterbridgeInformation.matterPasscode = await this.nodeContext?.get('matterpasscode');
2862
2321
  this.matterbridgeInformation.matterbridgePaired = this.matterbridgePaired;
2863
2322
  this.matterbridgeInformation.matterbridgeConnected = this.matterbridgeConnected;
2864
2323
  this.matterbridgeInformation.matterbridgeQrPairingCode = this.matterbridgeQrPairingCode;
@@ -2867,17 +2326,13 @@ export class Matterbridge extends EventEmitter {
2867
2326
  this.matterbridgeInformation.matterbridgeSessionInformations = Array.from(this.matterbridgeSessionInformations.values());
2868
2327
  this.matterbridgeInformation.profile = this.profile;
2869
2328
  const response = { wssHost, ssl: hasParameter('ssl'), systemInformation: this.systemInformation, matterbridgeInformation: this.matterbridgeInformation };
2870
- // this.log.debug('Response:', debugStringify(response));
2871
2329
  res.json(response);
2872
2330
  });
2873
- // Endpoint to provide plugins
2874
2331
  this.expressApp.get('/api/plugins', async (req, res) => {
2875
2332
  this.log.debug('The frontend sent /api/plugins');
2876
2333
  const response = await this.getBaseRegisteredPlugins();
2877
- // this.log.debug('Response:', debugStringify(response));
2878
2334
  res.json(response);
2879
2335
  });
2880
- // Endpoint to provide devices
2881
2336
  this.expressApp.get('/api/devices', (req, res) => {
2882
2337
  this.log.debug('The frontend sent /api/devices');
2883
2338
  const data = [];
@@ -2891,6 +2346,9 @@ export class Matterbridge extends EventEmitter {
2891
2346
  let serial = device.getClusterServer(BasicInformationCluster)?.attributes.serialNumber?.getLocal();
2892
2347
  if (!serial)
2893
2348
  serial = device.getClusterServer(BridgedDeviceBasicInformationCluster)?.attributes.serialNumber?.getLocal() ?? 'Unknown';
2349
+ let productUrl = device.getClusterServer(BasicInformationCluster)?.attributes.productUrl?.getLocal();
2350
+ if (!productUrl)
2351
+ productUrl = device.getClusterServer(BridgedDeviceBasicInformationCluster)?.attributes.productUrl?.getLocal() ?? 'Unknown';
2894
2352
  let uniqueId = device.getClusterServer(BasicInformationCluster)?.attributes.uniqueId?.getLocal();
2895
2353
  if (!uniqueId)
2896
2354
  uniqueId = device.getClusterServer(BridgedDeviceBasicInformationCluster)?.attributes.uniqueId?.getLocal() ?? 'Unknown';
@@ -2901,14 +2359,14 @@ export class Matterbridge extends EventEmitter {
2901
2359
  endpoint: device.number,
2902
2360
  name,
2903
2361
  serial,
2362
+ productUrl,
2363
+ configUrl: device.configUrl,
2904
2364
  uniqueId,
2905
2365
  cluster: cluster,
2906
2366
  });
2907
2367
  });
2908
- // this.log.debug('Response:', debugStringify(data));
2909
2368
  res.json(data);
2910
2369
  });
2911
- // Endpoint to provide the cluster servers of the devices
2912
2370
  this.expressApp.get('/api/devices_clusters/:selectedPluginName/:selectedDeviceEndpoint', (req, res) => {
2913
2371
  const selectedPluginName = req.params.selectedPluginName;
2914
2372
  const selectedDeviceEndpoint = parseInt(req.params.selectedDeviceEndpoint, 10);
@@ -2928,7 +2386,6 @@ export class Matterbridge extends EventEmitter {
2928
2386
  Object.entries(clusterServer.attributes).forEach(([key, value]) => {
2929
2387
  if (clusterServer.name === 'EveHistory')
2930
2388
  return;
2931
- // this.log.debug(`***--clusterServer: ${clusterServer.name}(${clusterServer.id}) attribute:${key}(${value.id}) ${value.isFixed} ${value.isWritable} ${value.isWritable}`);
2932
2389
  let attributeValue;
2933
2390
  try {
2934
2391
  if (typeof value.getLocal() === 'object')
@@ -2939,7 +2396,6 @@ export class Matterbridge extends EventEmitter {
2939
2396
  catch (error) {
2940
2397
  attributeValue = 'Fabric-Scoped';
2941
2398
  this.log.debug(`GetLocal value ${error} in clusterServer: ${clusterServer.name}(${clusterServer.id}) attribute: ${key}(${value.id})`);
2942
- // console.log(error);
2943
2399
  }
2944
2400
  data.push({
2945
2401
  endpoint: device.number ? device.number.toString() : '...',
@@ -2952,14 +2408,12 @@ export class Matterbridge extends EventEmitter {
2952
2408
  });
2953
2409
  });
2954
2410
  device.getChildEndpoints().forEach((childEndpoint) => {
2955
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
2956
2411
  const name = this.edge ? childEndpoint.endpoint?.id : childEndpoint.uniqueStorageKey;
2957
2412
  const clusterServers = childEndpoint.getAllClusterServers();
2958
2413
  clusterServers.forEach((clusterServer) => {
2959
2414
  Object.entries(clusterServer.attributes).forEach(([key, value]) => {
2960
2415
  if (clusterServer.name === 'EveHistory')
2961
2416
  return;
2962
- // this.log.debug(`***--clusterServer: ${clusterServer.name}(${clusterServer.id}) attribute:${key}(${value.id}) ${value.isFixed} ${value.isWritable} ${value.isWritable}`);
2963
2417
  let attributeValue;
2964
2418
  try {
2965
2419
  if (typeof value.getLocal() === 'object')
@@ -2970,7 +2424,6 @@ export class Matterbridge extends EventEmitter {
2970
2424
  catch (error) {
2971
2425
  attributeValue = 'Unavailable';
2972
2426
  this.log.debug(`GetLocal error ${error} in clusterServer: ${clusterServer.name}(${clusterServer.id}) attribute: ${key}(${value.id})`);
2973
- // console.log(error);
2974
2427
  }
2975
2428
  data.push({
2976
2429
  endpoint: (childEndpoint.number ? childEndpoint.number.toString() : '...') + (name ? ' (' + name + ')' : ''),
@@ -2987,7 +2440,6 @@ export class Matterbridge extends EventEmitter {
2987
2440
  });
2988
2441
  res.json(data);
2989
2442
  });
2990
- // Endpoint to view the log
2991
2443
  this.expressApp.get('/api/view-log', async (req, res) => {
2992
2444
  this.log.debug('The frontend sent /api/log');
2993
2445
  try {
@@ -3000,12 +2452,10 @@ export class Matterbridge extends EventEmitter {
3000
2452
  res.status(500).send('Error reading log file');
3001
2453
  }
3002
2454
  });
3003
- // Endpoint to download the matterbridge log
3004
2455
  this.expressApp.get('/api/download-mblog', async (req, res) => {
3005
2456
  this.log.debug('The frontend sent /api/download-mblog');
3006
2457
  try {
3007
2458
  await fs.access(path.join(this.matterbridgeDirectory, this.matterbrideLoggerFile), fs.constants.F_OK);
3008
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
3009
2459
  }
3010
2460
  catch (error) {
3011
2461
  fs.appendFile(path.join(this.matterbridgeDirectory, this.matterbrideLoggerFile), 'Enable the log on file in the settings to enable the file logger');
@@ -3017,12 +2467,10 @@ export class Matterbridge extends EventEmitter {
3017
2467
  }
3018
2468
  });
3019
2469
  });
3020
- // Endpoint to download the matter log
3021
2470
  this.expressApp.get('/api/download-mjlog', async (req, res) => {
3022
2471
  this.log.debug('The frontend sent /api/download-mjlog');
3023
2472
  try {
3024
2473
  await fs.access(path.join(this.matterbridgeDirectory, this.matterLoggerFile), fs.constants.F_OK);
3025
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
3026
2474
  }
3027
2475
  catch (error) {
3028
2476
  fs.appendFile(path.join(this.matterbridgeDirectory, this.matterLoggerFile), 'Enable the log on file in the settings to enable the file logger');
@@ -3034,7 +2482,6 @@ export class Matterbridge extends EventEmitter {
3034
2482
  }
3035
2483
  });
3036
2484
  });
3037
- // Endpoint to download the matter storage file
3038
2485
  this.expressApp.get('/api/download-mjstorage', (req, res) => {
3039
2486
  this.log.debug('The frontend sent /api/download-mjstorage');
3040
2487
  res.download(path.join(this.matterbridgeDirectory, this.matterStorageName), 'matterbridge.json', (error) => {
@@ -3044,7 +2491,6 @@ export class Matterbridge extends EventEmitter {
3044
2491
  }
3045
2492
  });
3046
2493
  });
3047
- // Endpoint to download the matterbridge storage directory
3048
2494
  this.expressApp.get('/api/download-mbstorage', async (req, res) => {
3049
2495
  this.log.debug('The frontend sent /api/download-mbstorage');
3050
2496
  await createZip(path.join(os.tmpdir(), `matterbridge.${this.nodeStorageName}.zip`), path.join(this.matterbridgeDirectory, this.nodeStorageName));
@@ -3055,7 +2501,6 @@ export class Matterbridge extends EventEmitter {
3055
2501
  }
3056
2502
  });
3057
2503
  });
3058
- // Endpoint to download the matterbridge plugin directory
3059
2504
  this.expressApp.get('/api/download-pluginstorage', async (req, res) => {
3060
2505
  this.log.debug('The frontend sent /api/download-pluginstorage');
3061
2506
  await createZip(path.join(os.tmpdir(), `matterbridge.pluginstorage.zip`), this.matterbridgePluginDirectory);
@@ -3066,11 +2511,9 @@ export class Matterbridge extends EventEmitter {
3066
2511
  }
3067
2512
  });
3068
2513
  });
3069
- // Endpoint to download the matterbridge plugin config files
3070
2514
  this.expressApp.get('/api/download-pluginconfig', async (req, res) => {
3071
2515
  this.log.debug('The frontend sent /api/download-pluginconfig');
3072
2516
  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
2517
  res.download(path.join(os.tmpdir(), `matterbridge.pluginconfig.zip`), `matterbridge.pluginconfig.zip`, (error) => {
3075
2518
  if (error) {
3076
2519
  this.log.error(`Error downloading file matterbridge.pluginstorage.zip: ${error instanceof Error ? error.message : error}`);
@@ -3078,7 +2521,6 @@ export class Matterbridge extends EventEmitter {
3078
2521
  }
3079
2522
  });
3080
2523
  });
3081
- // Endpoint to download the matterbridge plugin config files
3082
2524
  this.expressApp.get('/api/download-backup', async (req, res) => {
3083
2525
  this.log.debug('The frontend sent /api/download-backup');
3084
2526
  res.download(path.join(os.tmpdir(), `matterbridge.backup.zip`), `matterbridge.backup.zip`, (error) => {
@@ -3088,7 +2530,6 @@ export class Matterbridge extends EventEmitter {
3088
2530
  }
3089
2531
  });
3090
2532
  });
3091
- // Endpoint to receive commands
3092
2533
  this.expressApp.post('/api/command/:command/:param', express.json(), async (req, res) => {
3093
2534
  const command = req.params.command;
3094
2535
  let param = req.params.param;
@@ -3098,15 +2539,13 @@ export class Matterbridge extends EventEmitter {
3098
2539
  return;
3099
2540
  }
3100
2541
  this.log.debug(`Received frontend command: ${command}:${param}`);
3101
- // Handle the command setpassword from Settings
3102
2542
  if (command === 'setpassword') {
3103
- const password = param.slice(1, -1); // Remove the first and last characters
2543
+ const password = param.slice(1, -1);
3104
2544
  this.log.debug('setpassword', param, password);
3105
2545
  await this.nodeContext?.set('password', password);
3106
2546
  res.json({ message: 'Command received' });
3107
2547
  return;
3108
2548
  }
3109
- // Handle the command setbridgemode from Settings
3110
2549
  if (command === 'setbridgemode') {
3111
2550
  this.log.debug(`setbridgemode: ${param}`);
3112
2551
  this.wssSendRestartRequired();
@@ -3114,7 +2553,6 @@ export class Matterbridge extends EventEmitter {
3114
2553
  res.json({ message: 'Command received' });
3115
2554
  return;
3116
2555
  }
3117
- // Handle the command backup from Settings
3118
2556
  if (command === 'backup') {
3119
2557
  this.log.notice(`Prepairing the backup...`);
3120
2558
  await createZip(path.join(os.tmpdir(), `matterbridge.backup.zip`), path.join(this.matterbridgeDirectory), path.join(this.matterbridgePluginDirectory));
@@ -3122,26 +2560,25 @@ export class Matterbridge extends EventEmitter {
3122
2560
  res.json({ message: 'Command received' });
3123
2561
  return;
3124
2562
  }
3125
- // Handle the command setmbloglevel from Settings
3126
2563
  if (command === 'setmbloglevel') {
3127
2564
  this.log.debug('Matterbridge log level:', param);
3128
2565
  if (param === 'Debug') {
3129
- this.log.logLevel = "debug" /* LogLevel.DEBUG */;
2566
+ this.log.logLevel = "debug";
3130
2567
  }
3131
2568
  else if (param === 'Info') {
3132
- this.log.logLevel = "info" /* LogLevel.INFO */;
2569
+ this.log.logLevel = "info";
3133
2570
  }
3134
2571
  else if (param === 'Notice') {
3135
- this.log.logLevel = "notice" /* LogLevel.NOTICE */;
2572
+ this.log.logLevel = "notice";
3136
2573
  }
3137
2574
  else if (param === 'Warn') {
3138
- this.log.logLevel = "warn" /* LogLevel.WARN */;
2575
+ this.log.logLevel = "warn";
3139
2576
  }
3140
2577
  else if (param === 'Error') {
3141
- this.log.logLevel = "error" /* LogLevel.ERROR */;
2578
+ this.log.logLevel = "error";
3142
2579
  }
3143
2580
  else if (param === 'Fatal') {
3144
- this.log.logLevel = "fatal" /* LogLevel.FATAL */;
2581
+ this.log.logLevel = "fatal";
3145
2582
  }
3146
2583
  await this.nodeContext?.set('matterbridgeLogLevel', this.log.logLevel);
3147
2584
  MatterbridgeDevice.logLevel = this.log.logLevel;
@@ -3149,13 +2586,12 @@ export class Matterbridge extends EventEmitter {
3149
2586
  for (const plugin of this.plugins) {
3150
2587
  if (!plugin.platform || !plugin.platform.config)
3151
2588
  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);
2589
+ plugin.platform.log.logLevel = plugin.platform.config.debug ? "debug" : this.log.logLevel;
2590
+ await plugin.platform.onChangeLoggerLevel(plugin.platform.config.debug ? "debug" : this.log.logLevel);
3154
2591
  }
3155
2592
  res.json({ message: 'Command received' });
3156
2593
  return;
3157
2594
  }
3158
- // Handle the command setmbloglevel from Settings
3159
2595
  if (command === 'setmjloglevel') {
3160
2596
  this.log.debug('Matter.js log level:', param);
3161
2597
  if (param === 'Debug') {
@@ -3180,47 +2616,65 @@ export class Matterbridge extends EventEmitter {
3180
2616
  res.json({ message: 'Command received' });
3181
2617
  return;
3182
2618
  }
3183
- // Handle the command setmdnsinterface from Settings
3184
2619
  if (command === 'setmdnsinterface') {
3185
- param = param.slice(1, -1); // Remove the first and last characters *mdns*
2620
+ param = param.slice(1, -1);
3186
2621
  this.matterbridgeInformation.mattermdnsinterface = param;
3187
2622
  this.log.debug('Matter.js mdns interface:', param === '' ? 'All interfaces' : param);
3188
2623
  await this.nodeContext?.set('mattermdnsinterface', param);
3189
2624
  res.json({ message: 'Command received' });
3190
2625
  return;
3191
2626
  }
3192
- // Handle the command setipv4address from Settings
3193
2627
  if (command === 'setipv4address') {
3194
- param = param.slice(1, -1); // Remove the first and last characters *ip*
2628
+ param = param.slice(1, -1);
3195
2629
  this.matterbridgeInformation.matteripv4address = param;
3196
2630
  this.log.debug('Matter.js ipv4 address:', param === '' ? 'All ipv4 addresses' : param);
3197
2631
  await this.nodeContext?.set('matteripv4address', param);
3198
2632
  res.json({ message: 'Command received' });
3199
2633
  return;
3200
2634
  }
3201
- // Handle the command setipv6address from Settings
3202
2635
  if (command === 'setipv6address') {
3203
- param = param.slice(1, -1); // Remove the first and last characters *ip*
2636
+ param = param.slice(1, -1);
3204
2637
  this.matterbridgeInformation.matteripv6address = param;
3205
2638
  this.log.debug('Matter.js ipv6 address:', param === '' ? 'All ipv6 addresses' : param);
3206
2639
  await this.nodeContext?.set('matteripv6address', param);
3207
2640
  res.json({ message: 'Command received' });
3208
2641
  return;
3209
2642
  }
3210
- // Handle the command setmbloglevel from Settings
2643
+ if (command === 'setmatterport') {
2644
+ const port = Math.min(Math.max(parseInt(param), 5540), 5560);
2645
+ this.matterbridgeInformation.matterPort = port;
2646
+ this.log.debug(`Set matter commissioning port to ${CYAN}${port}${db}`);
2647
+ await this.nodeContext?.set('matterport', port);
2648
+ res.json({ message: 'Command received' });
2649
+ return;
2650
+ }
2651
+ if (command === 'setmatterdiscriminator') {
2652
+ const discriminator = Math.min(Math.max(parseInt(param), 1000), 4095);
2653
+ this.matterbridgeInformation.matterDiscriminator = discriminator;
2654
+ this.log.debug(`Set matter commissioning discriminator to ${CYAN}${discriminator}${db}`);
2655
+ await this.nodeContext?.set('matterdiscriminator', discriminator);
2656
+ res.json({ message: 'Command received' });
2657
+ return;
2658
+ }
2659
+ if (command === 'setmatterpasscode') {
2660
+ const passcode = Math.min(Math.max(parseInt(param), 10000000), 90000000);
2661
+ this.matterbridgeInformation.matterPasscode = passcode;
2662
+ this.log.debug(`Set matter commissioning passcode to ${CYAN}${passcode}${db}`);
2663
+ await this.nodeContext?.set('matterpasscode', passcode);
2664
+ res.json({ message: 'Command received' });
2665
+ return;
2666
+ }
3211
2667
  if (command === 'setmblogfile') {
3212
2668
  this.log.debug('Matterbridge file log:', param);
3213
2669
  this.matterbridgeInformation.fileLogger = param === 'true';
3214
2670
  await this.nodeContext?.set('matterbridgeFileLog', param === 'true');
3215
- // Create the file logger for matterbridge
3216
2671
  if (param === 'true')
3217
- AnsiLogger.setGlobalLogfile(path.join(this.matterbridgeDirectory, this.matterbrideLoggerFile), "debug" /* LogLevel.DEBUG */, true);
2672
+ AnsiLogger.setGlobalLogfile(path.join(this.matterbridgeDirectory, this.matterbrideLoggerFile), "debug", true);
3218
2673
  else
3219
2674
  AnsiLogger.setGlobalLogfile(undefined);
3220
2675
  res.json({ message: 'Command received' });
3221
2676
  return;
3222
2677
  }
3223
- // Handle the command setmbloglevel from Settings
3224
2678
  if (command === 'setmjlogfile') {
3225
2679
  this.log.debug('Matter file log:', param);
3226
2680
  this.matterbridgeInformation.matterFileLogger = param === 'true';
@@ -3247,43 +2701,36 @@ export class Matterbridge extends EventEmitter {
3247
2701
  res.json({ message: 'Command received' });
3248
2702
  return;
3249
2703
  }
3250
- // Handle the command unregister from Settings
3251
2704
  if (command === 'unregister') {
3252
2705
  await this.unregisterAndShutdownProcess();
3253
2706
  res.json({ message: 'Command received' });
3254
2707
  return;
3255
2708
  }
3256
- // Handle the command reset from Settings
3257
2709
  if (command === 'reset') {
3258
2710
  await this.shutdownProcessAndReset();
3259
2711
  res.json({ message: 'Command received' });
3260
2712
  return;
3261
2713
  }
3262
- // Handle the command factoryreset from Settings
3263
2714
  if (command === 'factoryreset') {
3264
2715
  await this.shutdownProcessAndFactoryReset();
3265
2716
  res.json({ message: 'Command received' });
3266
2717
  return;
3267
2718
  }
3268
- // Handle the command shutdown from Header
3269
2719
  if (command === 'shutdown') {
3270
2720
  await this.shutdownProcess();
3271
2721
  res.json({ message: 'Command received' });
3272
2722
  return;
3273
2723
  }
3274
- // Handle the command restart from Header
3275
2724
  if (command === 'restart') {
3276
2725
  await this.restartProcess();
3277
2726
  res.json({ message: 'Command received' });
3278
2727
  return;
3279
2728
  }
3280
- // Handle the command update from Header
3281
2729
  if (command === 'update') {
3282
2730
  this.log.info('Updating matterbridge...');
3283
2731
  try {
3284
2732
  await this.spawnCommand('npm', ['install', '-g', 'matterbridge', '--omit=dev', '--verbose']);
3285
2733
  this.log.info('Matterbridge has been updated. Full restart required.');
3286
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
3287
2734
  }
3288
2735
  catch (error) {
3289
2736
  this.log.error('Error updating matterbridge');
@@ -3293,11 +2740,9 @@ export class Matterbridge extends EventEmitter {
3293
2740
  res.json({ message: 'Command received' });
3294
2741
  return;
3295
2742
  }
3296
- // Handle the command saveconfig from Home
3297
2743
  if (command === 'saveconfig') {
3298
2744
  param = param.replace(/\*/g, '\\');
3299
2745
  this.log.info(`Saving config for plugin ${plg}${param}${nf}...`);
3300
- // console.log('Req.body:', JSON.stringify(req.body, null, 2));
3301
2746
  if (!this.plugins.has(param)) {
3302
2747
  this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
3303
2748
  }
@@ -3311,35 +2756,33 @@ export class Matterbridge extends EventEmitter {
3311
2756
  res.json({ message: 'Command received' });
3312
2757
  return;
3313
2758
  }
3314
- // Handle the command installplugin from Home
3315
2759
  if (command === 'installplugin') {
3316
2760
  param = param.replace(/\*/g, '\\');
3317
2761
  this.log.info(`Installing plugin ${plg}${param}${nf}...`);
3318
2762
  try {
3319
2763
  await this.spawnCommand('npm', ['install', '-g', param, '--omit=dev', '--verbose']);
3320
2764
  this.log.info(`Plugin ${plg}${param}${nf} installed. Full restart required.`);
3321
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
3322
2765
  }
3323
2766
  catch (error) {
3324
2767
  this.log.error(`Error installing plugin ${plg}${param}${er}`);
3325
2768
  }
3326
2769
  this.wssSendRestartRequired();
3327
- // Also add the plugin to matterbridge so no return!
3328
- // res.json({ message: 'Command received' });
3329
- // return;
2770
+ param = param.split('@')[0];
2771
+ if (param === 'matterbridge') {
2772
+ res.json({ message: 'Command received' });
2773
+ return;
2774
+ }
3330
2775
  }
3331
- // Handle the command addplugin from Home
3332
2776
  if (command === 'addplugin' || command === 'installplugin') {
3333
2777
  param = param.replace(/\*/g, '\\');
3334
2778
  const plugin = await this.plugins.add(param);
3335
2779
  if (plugin) {
3336
- this.plugins.load(plugin, true, 'The plugin has been added', true); // No await do it in the background
2780
+ this.plugins.load(plugin, true, 'The plugin has been added', true);
3337
2781
  }
3338
2782
  res.json({ message: 'Command received' });
3339
2783
  this.wssSendRefreshRequired();
3340
2784
  return;
3341
2785
  }
3342
- // Handle the command removeplugin from Home
3343
2786
  if (command === 'removeplugin') {
3344
2787
  if (!this.plugins.has(param)) {
3345
2788
  this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
@@ -3353,7 +2796,6 @@ export class Matterbridge extends EventEmitter {
3353
2796
  this.wssSendRefreshRequired();
3354
2797
  return;
3355
2798
  }
3356
- // Handle the command enableplugin from Home
3357
2799
  if (command === 'enableplugin') {
3358
2800
  if (!this.plugins.has(param)) {
3359
2801
  this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
@@ -3371,14 +2813,13 @@ export class Matterbridge extends EventEmitter {
3371
2813
  plugin.registeredDevices = undefined;
3372
2814
  plugin.addedDevices = undefined;
3373
2815
  await this.plugins.enable(param);
3374
- this.plugins.load(plugin, true, 'The plugin has been enabled', true); // No await do it in the background
2816
+ this.plugins.load(plugin, true, 'The plugin has been enabled', true);
3375
2817
  }
3376
2818
  }
3377
2819
  res.json({ message: 'Command received' });
3378
2820
  this.wssSendRefreshRequired();
3379
2821
  return;
3380
2822
  }
3381
- // Handle the command disableplugin from Home
3382
2823
  if (command === 'disableplugin') {
3383
2824
  if (!this.plugins.has(param)) {
3384
2825
  this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
@@ -3395,7 +2836,6 @@ export class Matterbridge extends EventEmitter {
3395
2836
  return;
3396
2837
  }
3397
2838
  });
3398
- // Fallback for routing (must be the last route)
3399
2839
  this.expressApp.get('*', (req, res) => {
3400
2840
  this.log.debug('The frontend sent:', req.url);
3401
2841
  this.log.debug('Response send file:', path.join(this.rootDirectory, 'frontend/build/index.html'));
@@ -3403,11 +2843,6 @@ export class Matterbridge extends EventEmitter {
3403
2843
  });
3404
2844
  this.log.debug(`Frontend initialized on port ${YELLOW}${port}${db} static ${UNDERLINE}${path.join(this.rootDirectory, 'frontend/build')}${UNDERLINEOFF}${rs}`);
3405
2845
  }
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
2846
  getClusterTextFromDevice(device) {
3412
2847
  const stringifyUserLabel = (endpoint) => {
3413
2848
  const labelList = endpoint.getClusterServer(UserLabelCluster)?.attributes.labelList.getLocal();
@@ -3430,11 +2865,9 @@ export class Matterbridge extends EventEmitter {
3430
2865
  return '';
3431
2866
  };
3432
2867
  let attributes = '';
3433
- // this.log.debug(`***getClusterTextFromDevice: ${device.deviceName} (${device.name})`);
3434
2868
  const clusterServers = device.getAllClusterServers();
3435
2869
  clusterServers.forEach((clusterServer) => {
3436
2870
  try {
3437
- // this.log.debug(`**--clusterServer: ${clusterServer.id} (${clusterServer.name})`);
3438
2871
  if (clusterServer.name === 'OnOff')
3439
2872
  attributes += `OnOff: ${clusterServer.attributes.onOff.getLocal()} `;
3440
2873
  if (clusterServer.name === 'Switch')
@@ -3485,30 +2918,18 @@ export class Matterbridge extends EventEmitter {
3485
2918
  attributes += `${stringifyFixedLabel(device)} `;
3486
2919
  if (clusterServer.name === 'UserLabel')
3487
2920
  attributes += `${stringifyUserLabel(device)} `;
3488
- // this.log.debug(`*--clusterServer: ${clusterServer.id} (${clusterServer.name})`);
3489
2921
  }
3490
2922
  catch (error) {
3491
2923
  this.log.error(`getClusterTextFromDevice with ${clusterServer.name} error: ${error}`);
3492
2924
  }
3493
2925
  });
3494
- // this.log.debug(`*getClusterTextFromDevice: ${device.deviceName} (${device.name})`);
3495
2926
  return attributes;
3496
2927
  }
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
2928
  async startExtension(dataPath, extensionVersion, port = 5540) {
3504
- // Set the bridge mode
3505
2929
  this.bridgeMode = 'bridge';
3506
- // Set the first port to use
3507
2930
  this.port = port;
3508
- // Set Matterbridge logger
3509
- this.log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: "info" /* LogLevel.INFO */ });
2931
+ this.log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4, logLevel: "info" });
3510
2932
  this.log.debug('Matterbridge extension is starting...');
3511
- // Initialize NodeStorage
3512
2933
  this.matterbridgeDirectory = dataPath;
3513
2934
  this.log.debug('Creating node storage manager dir: ' + path.join(this.matterbridgeDirectory, 'node_storage'));
3514
2935
  this.nodeStorage = new NodeStorageManager({ dir: path.join(this.matterbridgeDirectory, 'node_storage'), logging: false });
@@ -3527,13 +2948,10 @@ export class Matterbridge extends EventEmitter {
3527
2948
  };
3528
2949
  this.plugins.set(plugin);
3529
2950
  this.plugins.saveToStorage();
3530
- // Log system info and create .matterbridge directory
3531
2951
  await this.logNodeAndSystemInfo();
3532
2952
  this.matterbridgeDirectory = dataPath;
3533
- // Set matter.js logger level and format
3534
2953
  Logger.defaultLogLevel = MatterLogLevel.INFO;
3535
2954
  Logger.format = MatterLogFormat.ANSI;
3536
- // Start the storage and create matterbridgeContext
3537
2955
  await this.startMatterStorage('json', path.join(this.matterbridgeDirectory, this.matterStorageName));
3538
2956
  if (!this.storageManager)
3539
2957
  return false;
@@ -3543,7 +2961,7 @@ export class Matterbridge extends EventEmitter {
3543
2961
  await this.matterbridgeContext.set('softwareVersion', 1);
3544
2962
  await this.matterbridgeContext.set('softwareVersionString', this.matterbridgeVersion);
3545
2963
  await this.matterbridgeContext.set('hardwareVersion', 1);
3546
- await this.matterbridgeContext.set('hardwareVersionString', extensionVersion); // Update with the extension version
2964
+ await this.matterbridgeContext.set('hardwareVersionString', extensionVersion);
3547
2965
  this.matterServer = this.createMatterServer(this.storageManager);
3548
2966
  this.log.debug(`Creating commissioning server for ${plg}Matterbridge${db}`);
3549
2967
  this.commissioningServer = await this.createCommisioningServer(this.matterbridgeContext, 'Matterbridge');
@@ -3556,7 +2974,6 @@ export class Matterbridge extends EventEmitter {
3556
2974
  await this.startMatterServer();
3557
2975
  this.log.info('Matter server started');
3558
2976
  await this.showCommissioningQRCode(this.commissioningServer, this.matterbridgeContext, this.nodeContext, 'Matterbridge');
3559
- // Set reachability to true and trigger event after 60 seconds
3560
2977
  setTimeout(() => {
3561
2978
  this.log.info(`Setting reachability to true for ${plg}Matterbridge${db}`);
3562
2979
  if (this.commissioningServer)
@@ -3566,31 +2983,14 @@ export class Matterbridge extends EventEmitter {
3566
2983
  }, 60 * 1000);
3567
2984
  return this.commissioningServer.isCommissioned();
3568
2985
  }
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
2986
  async stopExtension() {
3576
- // Closing matter
3577
2987
  await this.stopMatterServer();
3578
- // Clearing the session manager
3579
- // this.matterbridgeContext?.createContext('SessionManager').clear();
3580
- // Closing storage
3581
2988
  await this.stopMatterStorage();
3582
2989
  this.log.info('Matter server stopped');
3583
2990
  }
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
2991
  isExtensionCommissioned() {
3591
2992
  if (!this.commissioningServer)
3592
2993
  return false;
3593
2994
  return this.commissioningServer.isCommissioned();
3594
2995
  }
3595
2996
  }
3596
- //# sourceMappingURL=matterbridge.js.map