matterbridge 1.6.8-dev.6 → 1.6.8-dev.8

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 (82) hide show
  1. package/CHANGELOG.md +2 -2
  2. package/dist/cli.js +0 -26
  3. package/dist/cluster/export.js +0 -2
  4. package/dist/defaultConfigSchema.js +0 -23
  5. package/dist/deviceManager.js +1 -26
  6. package/dist/index.js +0 -30
  7. package/dist/logger/export.js +0 -1
  8. package/dist/matter/export.js +0 -1
  9. package/dist/matterbridge.js +189 -812
  10. package/dist/matterbridgeAccessoryPlatform.js +0 -33
  11. package/dist/matterbridgeBehaviors.js +1 -29
  12. package/dist/matterbridgeDevice.js +10 -997
  13. package/dist/matterbridgeDeviceTypes.js +11 -82
  14. package/dist/matterbridgeDynamicPlatform.js +0 -33
  15. package/dist/matterbridgeEdge.js +0 -529
  16. package/dist/matterbridgeEndpoint.js +12 -1121
  17. package/dist/matterbridgePlatform.js +3 -99
  18. package/dist/matterbridgeTypes.js +0 -24
  19. package/dist/matterbridgeWebsocket.js +0 -45
  20. package/dist/pluginManager.js +3 -238
  21. package/dist/storage/export.js +0 -1
  22. package/dist/utils/colorUtils.js +2 -205
  23. package/dist/utils/export.js +0 -1
  24. package/dist/utils/utils.js +8 -253
  25. package/npm-shrinkwrap.json +8 -8
  26. package/package.json +1 -1
  27. package/dist/cli.d.ts.map +0 -1
  28. package/dist/cli.js.map +0 -1
  29. package/dist/cluster/export.d.ts.map +0 -1
  30. package/dist/cluster/export.js.map +0 -1
  31. package/dist/defaultConfigSchema.d.ts.map +0 -1
  32. package/dist/defaultConfigSchema.js.map +0 -1
  33. package/dist/deviceManager.d.ts +0 -46
  34. package/dist/deviceManager.d.ts.map +0 -1
  35. package/dist/deviceManager.js.map +0 -1
  36. package/dist/index.d.ts.map +0 -1
  37. package/dist/index.js.map +0 -1
  38. package/dist/logger/export.d.ts.map +0 -1
  39. package/dist/logger/export.js.map +0 -1
  40. package/dist/matter/export.d.ts.map +0 -1
  41. package/dist/matter/export.js.map +0 -1
  42. package/dist/matterbridge.d.ts +0 -473
  43. package/dist/matterbridge.d.ts.map +0 -1
  44. package/dist/matterbridge.js.map +0 -1
  45. package/dist/matterbridgeAccessoryPlatform.d.ts.map +0 -1
  46. package/dist/matterbridgeAccessoryPlatform.js.map +0 -1
  47. package/dist/matterbridgeBehaviors.d.ts +0 -116
  48. package/dist/matterbridgeBehaviors.d.ts.map +0 -1
  49. package/dist/matterbridgeBehaviors.js.map +0 -1
  50. package/dist/matterbridgeDevice.d.ts +0 -1142
  51. package/dist/matterbridgeDevice.d.ts.map +0 -1
  52. package/dist/matterbridgeDevice.js.map +0 -1
  53. package/dist/matterbridgeDeviceTypes.d.ts +0 -109
  54. package/dist/matterbridgeDeviceTypes.d.ts.map +0 -1
  55. package/dist/matterbridgeDeviceTypes.js.map +0 -1
  56. package/dist/matterbridgeDynamicPlatform.d.ts.map +0 -1
  57. package/dist/matterbridgeDynamicPlatform.js.map +0 -1
  58. package/dist/matterbridgeEdge.d.ts +0 -90
  59. package/dist/matterbridgeEdge.d.ts.map +0 -1
  60. package/dist/matterbridgeEdge.js.map +0 -1
  61. package/dist/matterbridgeEndpoint.d.ts +0 -1134
  62. package/dist/matterbridgeEndpoint.d.ts.map +0 -1
  63. package/dist/matterbridgeEndpoint.js.map +0 -1
  64. package/dist/matterbridgePlatform.d.ts +0 -123
  65. package/dist/matterbridgePlatform.d.ts.map +0 -1
  66. package/dist/matterbridgePlatform.js.map +0 -1
  67. package/dist/matterbridgeTypes.d.ts.map +0 -1
  68. package/dist/matterbridgeTypes.js.map +0 -1
  69. package/dist/matterbridgeWebsocket.d.ts.map +0 -1
  70. package/dist/matterbridgeWebsocket.js.map +0 -1
  71. package/dist/pluginManager.d.ts +0 -238
  72. package/dist/pluginManager.d.ts.map +0 -1
  73. package/dist/pluginManager.js.map +0 -1
  74. package/dist/storage/export.d.ts.map +0 -1
  75. package/dist/storage/export.js.map +0 -1
  76. package/dist/utils/colorUtils.d.ts.map +0 -1
  77. package/dist/utils/colorUtils.js.map +0 -1
  78. package/dist/utils/export.d.ts.map +0 -1
  79. package/dist/utils/export.js.map +0 -1
  80. package/dist/utils/utils.d.ts +0 -221
  81. package/dist/utils/utils.d.ts.map +0 -1
  82. package/dist/utils/utils.js.map +0 -1
@@ -1,26 +1,3 @@
1
- /**
2
- * This file contains the class Matterbridge.
3
- *
4
- * @file matterbridge.ts
5
- * @author Luca Liguori
6
- * @date 2023-12-29
7
- * @version 1.5.2
8
- *
9
- * Copyright 2023, 2024, 2025 Luca Liguori.
10
- *
11
- * Licensed under the Apache License, Version 2.0 (the "License");
12
- * you may not use this file except in compliance with the License.
13
- * You may obtain a copy of the License at
14
- *
15
- * http://www.apache.org/licenses/LICENSE-2.0
16
- *
17
- * Unless required by applicable law or agreed to in writing, software
18
- * distributed under the License is distributed on an "AS IS" BASIS,
19
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20
- * See the License for the specific language governing permissions and
21
- * limitations under the License. *
22
- */
23
- // Node.js modules
24
1
  import { fileURLToPath } from 'url';
25
2
  import { promises as fs } from 'fs';
26
3
  import { exec, spawn } from 'child_process';
@@ -29,36 +6,27 @@ import EventEmitter from 'events';
29
6
  import os from 'os';
30
7
  import path from 'path';
31
8
  import { randomBytes } from 'crypto';
32
- // Package modules
33
9
  import https from 'https';
34
10
  import express from 'express';
35
11
  import WebSocket, { WebSocketServer } from 'ws';
36
- // NodeStorage and AnsiLogger modules
37
12
  import { NodeStorageManager } from 'node-persist-manager';
38
13
  import { AnsiLogger, UNDERLINE, UNDERLINEOFF, YELLOW, db, debugStringify, stringify, BRIGHT, RESET, er, nf, rs, wr, RED, GREEN, zb, CYAN, nt, idn, or, hk, BLUE } from 'node-ansi-logger';
39
- // Matterbridge
40
14
  import { MatterbridgeDevice } from './matterbridgeDevice.js';
41
15
  import { WS_ID_LOG, WS_ID_REFRESH_NEEDED, WS_ID_RESTART_NEEDED, wsMessageHandler } from './matterbridgeWebsocket.js';
42
16
  import { logInterfaces, wait, waiter, createZip, copyDirectory, getParameter, getIntParameter, hasParameter } from './utils/utils.js';
43
17
  import { PluginManager } from './pluginManager.js';
44
18
  import { DeviceManager } from './deviceManager.js';
45
19
  import { MatterbridgeEndpoint } from './matterbridgeEndpoint.js';
46
- // @matter
47
20
  import { DeviceTypeId, Logger, LogLevel as MatterLogLevel, LogFormat as MatterLogFormat, VendorId, StorageManager, EndpointServer, StorageService, Environment } from '@matter/main';
48
21
  import { BasicInformationCluster, BridgedDeviceBasicInformation, BridgedDeviceBasicInformationCluster, FixedLabelCluster, GeneralCommissioning, PowerSourceCluster, SwitchCluster, ThreadNetworkDiagnosticsCluster, UserLabelCluster, } from '@matter/main/clusters';
49
22
  import { getClusterNameById, ManualPairingCodeCodec, QrCodeSchema } from '@matter/main/types';
50
23
  import { StorageBackendDisk, StorageBackendJsonFile } from '@matter/nodejs';
51
- // @project-chip
52
24
  import { CommissioningController, CommissioningServer, MatterServer } from '@project-chip/matter.js';
53
25
  import { Aggregator, DeviceTypes, NodeStateInformation } from '@project-chip/matter.js/device';
54
26
  import { aggregator } from './matterbridgeDeviceTypes.js';
55
- // Default colors
56
27
  const plg = '\u001B[38;5;33m';
57
28
  const dev = '\u001B[38;5;79m';
58
29
  const typ = '\u001B[38;5;207m';
59
- /**
60
- * Represents the Matterbridge application.
61
- */
62
30
  export class Matterbridge extends EventEmitter {
63
31
  systemInformation = {
64
32
  interfaceName: '',
@@ -95,7 +63,7 @@ export class Matterbridge extends EventEmitter {
95
63
  edge: hasParameter('edge'),
96
64
  readOnly: hasParameter('readonly'),
97
65
  profile: getParameter('profile'),
98
- loggerLevel: "info" /* LogLevel.INFO */,
66
+ loggerLevel: "info",
99
67
  fileLogger: false,
100
68
  matterLoggerLevel: MatterLogLevel.INFO,
101
69
  matterFileLogger: false,
@@ -134,7 +102,6 @@ export class Matterbridge extends EventEmitter {
134
102
  nodeContext;
135
103
  matterStorageName = 'matterbridge' + (getParameter('profile') ? '.' + getParameter('profile') : '') + '.json';
136
104
  nodeStorageName = 'storage' + (getParameter('profile') ? '.' + getParameter('profile') : '');
137
- // Cleanup
138
105
  hasCleanupStarted = false;
139
106
  initialized = false;
140
107
  execRunningCount = 0;
@@ -146,18 +113,16 @@ export class Matterbridge extends EventEmitter {
146
113
  sigtermHandler;
147
114
  exceptionHandler;
148
115
  rejectionHandler;
149
- // Frontend
150
116
  expressApp;
151
117
  httpServer;
152
118
  httpsServer;
153
119
  webSocketServer;
154
- // Matter
155
- mdnsInterface; // matter server mdnsInterface: e.g. 'eth0' or 'wlan0' or 'WiFi'
156
- ipv4address; // matter commissioning server listeningAddressIpv4
157
- ipv6address; // matter commissioning server listeningAddressIpv6
158
- port = 5540; // first commissioning server port
159
- passcode; // first commissioning server passcode
160
- discriminator; // first commissioning server discriminator
120
+ mdnsInterface;
121
+ ipv4address;
122
+ ipv6address;
123
+ port = 5540;
124
+ passcode;
125
+ discriminator;
161
126
  storageManager;
162
127
  matterbridgeContext;
163
128
  mattercontrollerContext;
@@ -168,26 +133,13 @@ export class Matterbridge extends EventEmitter {
168
133
  aggregatorVendorId = VendorId(getIntParameter('vendorId') ?? 0xfff1);
169
134
  aggregatorProductId = getIntParameter('productId') ?? 0x8000;
170
135
  static instance;
171
- // We load asyncronously so is private
172
136
  constructor() {
173
137
  super();
174
- // Bind the handler to the instance
175
138
  this.matterbridgeMessageHandler = wsMessageHandler.bind(this);
176
139
  }
177
140
  matterbridgeMessageHandler;
178
- /** ***********************************************************************************************************************************/
179
- /** loadInstance() and cleanup() methods */
180
- /** ***********************************************************************************************************************************/
181
- /**
182
- * Loads an instance of the Matterbridge class.
183
- * If an instance already exists, return that instance.
184
- *
185
- * @param initialize - Whether to initialize the Matterbridge instance after loading.
186
- * @returns The loaded Matterbridge instance.
187
- */
188
141
  static async loadInstance(initialize = false) {
189
142
  if (!Matterbridge.instance) {
190
- // eslint-disable-next-line no-console
191
143
  if (hasParameter('debug'))
192
144
  console.log(GREEN + 'Creating a new instance of Matterbridge.', initialize ? 'Initializing...' : 'Not initializing...', rs);
193
145
  Matterbridge.instance = new Matterbridge();
@@ -196,11 +148,6 @@ export class Matterbridge extends EventEmitter {
196
148
  }
197
149
  return Matterbridge.instance;
198
150
  }
199
- /**
200
- * Call cleanup().
201
- * @deprecated This method is deprecated and is only used for jest tests.
202
- *
203
- */
204
151
  async destroyInstance() {
205
152
  await this.cleanup('destroying instance...', false);
206
153
  await waiter('destroying instance...', () => {
@@ -208,60 +155,39 @@ export class Matterbridge extends EventEmitter {
208
155
  }, false, 60000, 100, false);
209
156
  await wait(1000, 'Wait for the global node_modules and matterbridge version', false);
210
157
  }
211
- /**
212
- * Initializes the Matterbridge application.
213
- *
214
- * @remarks
215
- * This method performs the necessary setup and initialization steps for the Matterbridge application.
216
- * It displays the help information if the 'help' parameter is provided, sets up the logger, checks the
217
- * node version, registers signal handlers, initializes storage, and parses the command line.
218
- *
219
- * @returns A Promise that resolves when the initialization is complete.
220
- */
221
158
  async initialize() {
222
- // Set the restart mode
223
159
  if (hasParameter('service'))
224
160
  this.restartMode = 'service';
225
161
  if (hasParameter('docker'))
226
162
  this.restartMode = 'docker';
227
- // Set the matterbridge directory
228
163
  this.homeDirectory = getParameter('homedir') ?? os.homedir();
229
164
  this.matterbridgeDirectory = path.join(this.homeDirectory, '.matterbridge');
230
- // Create matterbridge logger
231
- this.log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: hasParameter('debug') ? "debug" /* LogLevel.DEBUG */ : "info" /* LogLevel.INFO */ });
232
- // Initialize nodeStorage and nodeContext
165
+ this.log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4, logLevel: hasParameter('debug') ? "debug" : "info" });
233
166
  try {
234
167
  this.log.debug(`Creating node storage manager: ${CYAN}${this.nodeStorageName}${db}`);
235
168
  this.nodeStorage = new NodeStorageManager({ dir: path.join(this.matterbridgeDirectory, this.nodeStorageName), writeQueue: false, expiredInterval: undefined, logging: false });
236
169
  this.log.debug('Creating node storage context for matterbridge');
237
170
  this.nodeContext = await this.nodeStorage.createStorage('matterbridge');
238
- // TODO: Remove this code when node-persist-manager is updated
239
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
240
171
  const keys = (await this.nodeStorage?.storage.keys());
241
172
  for (const key of keys) {
242
173
  this.log.debug(`Checking node storage manager key: ${CYAN}${key}${db}`);
243
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
244
174
  await this.nodeStorage?.storage.get(key);
245
175
  }
246
176
  const storages = await this.nodeStorage.getStorageNames();
247
177
  for (const storage of storages) {
248
178
  this.log.debug(`Checking storage: ${CYAN}${storage}${db}`);
249
179
  const nodeContext = await this.nodeStorage?.createStorage(storage);
250
- // TODO: Remove this code when node-persist-manager is updated
251
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
252
180
  const keys = (await nodeContext?.storage.keys());
253
181
  keys.forEach(async (key) => {
254
182
  this.log.debug(`Checking key: ${CYAN}${storage}:${key}${db}`);
255
183
  await nodeContext?.get(key);
256
184
  });
257
185
  }
258
- // Creating a backup of the node storage since it is not corrupted
259
186
  this.log.debug('Creating node storage backup...');
260
187
  await copyDirectory(path.join(this.matterbridgeDirectory, this.nodeStorageName), path.join(this.matterbridgeDirectory, this.nodeStorageName + '.backup'));
261
188
  this.log.debug('Created node storage backup');
262
189
  }
263
190
  catch (error) {
264
- // Restoring the backup of the node storage since it is corrupted
265
191
  this.log.error(`Error creating node storage manager and context: ${error instanceof Error ? error.message : error}`);
266
192
  if (hasParameter('norestore')) {
267
193
  this.log.fatal(`The matterbridge node storage is corrupted. Parameter -norestore found: exiting...`);
@@ -276,51 +202,45 @@ export class Matterbridge extends EventEmitter {
276
202
  this.log.fatal('Fatal error creating node storage manager and context for matterbridge');
277
203
  throw new Error('Fatal error creating node storage manager and context for matterbridge');
278
204
  }
279
- // Set the first port to use for the commissioning server (will be incremented in childbridge mode)
280
205
  this.port = getIntParameter('port') ?? (await this.nodeContext.get('matterport', 5540)) ?? 5540;
281
- // Set the first passcode to use for the commissioning server (will be incremented in childbridge mode)
282
206
  this.passcode = this.passcode ?? getIntParameter('passcode') ?? (await this.nodeContext.get('matterpasscode'));
283
- // Set the first discriminator to use for the commissioning server (will be incremented in childbridge mode)
284
207
  this.discriminator = this.discriminator ?? getIntParameter('discriminator') ?? (await this.nodeContext.get('matterdiscriminator'));
285
208
  this.log.debug(`Initializing commissioning server for Matterbridge... on port ${this.port} with passcode ${this.passcode} and discriminator ${this.discriminator}`);
286
- // Set matterbridge logger level (context: matterbridgeLogLevel)
287
209
  if (hasParameter('logger')) {
288
210
  const level = getParameter('logger');
289
211
  if (level === 'debug') {
290
- this.log.logLevel = "debug" /* LogLevel.DEBUG */;
212
+ this.log.logLevel = "debug";
291
213
  }
292
214
  else if (level === 'info') {
293
- this.log.logLevel = "info" /* LogLevel.INFO */;
215
+ this.log.logLevel = "info";
294
216
  }
295
217
  else if (level === 'notice') {
296
- this.log.logLevel = "notice" /* LogLevel.NOTICE */;
218
+ this.log.logLevel = "notice";
297
219
  }
298
220
  else if (level === 'warn') {
299
- this.log.logLevel = "warn" /* LogLevel.WARN */;
221
+ this.log.logLevel = "warn";
300
222
  }
301
223
  else if (level === 'error') {
302
- this.log.logLevel = "error" /* LogLevel.ERROR */;
224
+ this.log.logLevel = "error";
303
225
  }
304
226
  else if (level === 'fatal') {
305
- this.log.logLevel = "fatal" /* LogLevel.FATAL */;
227
+ this.log.logLevel = "fatal";
306
228
  }
307
229
  else {
308
230
  this.log.warn(`Invalid matterbridge logger level: ${level}. Using default level "info".`);
309
- this.log.logLevel = "info" /* LogLevel.INFO */;
231
+ this.log.logLevel = "info";
310
232
  }
311
233
  }
312
234
  else {
313
- this.log.logLevel = await this.nodeContext.get('matterbridgeLogLevel', "info" /* LogLevel.INFO */);
235
+ this.log.logLevel = await this.nodeContext.get('matterbridgeLogLevel', "info");
314
236
  }
315
237
  MatterbridgeDevice.logLevel = this.log.logLevel;
316
- // Create the file logger for matterbridge (context: matterbridgeFileLog)
317
238
  if (hasParameter('filelogger') || (await this.nodeContext.get('matterbridgeFileLog', false))) {
318
239
  AnsiLogger.setGlobalLogfile(path.join(this.matterbridgeDirectory, this.matterbrideLoggerFile), this.log.logLevel, true);
319
240
  this.matterbridgeInformation.fileLogger = true;
320
241
  }
321
242
  this.log.notice('Matterbridge is starting...');
322
243
  this.log.debug(`Matterbridge logLevel: ${this.log.logLevel} fileLoger: ${this.matterbridgeInformation.fileLogger}.`);
323
- // Set matter.js logger level, format and logger (context: matterLogLevel)
324
244
  if (hasParameter('matterlogger')) {
325
245
  const level = getParameter('matterlogger');
326
246
  if (level === 'debug') {
@@ -351,7 +271,6 @@ export class Matterbridge extends EventEmitter {
351
271
  }
352
272
  Logger.format = MatterLogFormat.ANSI;
353
273
  Logger.setLogger('default', this.createMatterLogger());
354
- // Create the file logger for matter.js (context: matterFileLog)
355
274
  if (hasParameter('matterfilelogger') || (await this.nodeContext.get('matterFileLog', false))) {
356
275
  this.matterbridgeInformation.matterFileLogger = true;
357
276
  Logger.addLogger('matterfilelogger', await this.createMatterFileLogger(path.join(this.matterbridgeDirectory, this.matterLoggerFile), true), {
@@ -360,7 +279,6 @@ export class Matterbridge extends EventEmitter {
360
279
  });
361
280
  }
362
281
  this.log.debug(`Matter logLevel: ${Logger.defaultLogLevel} fileLoger: ${this.matterbridgeInformation.matterFileLogger}.`);
363
- // Set the interface to use for the matter server mdnsInterface
364
282
  if (hasParameter('mdnsinterface')) {
365
283
  this.mdnsInterface = getParameter('mdnsinterface');
366
284
  }
@@ -369,7 +287,6 @@ export class Matterbridge extends EventEmitter {
369
287
  if (this.mdnsInterface === '')
370
288
  this.mdnsInterface = undefined;
371
289
  }
372
- // Set the listeningAddressIpv4 for the matter commissioning server
373
290
  if (hasParameter('ipv4address')) {
374
291
  this.ipv4address = getParameter('ipv4address');
375
292
  }
@@ -378,7 +295,6 @@ export class Matterbridge extends EventEmitter {
378
295
  if (this.ipv4address === '')
379
296
  this.ipv4address = undefined;
380
297
  }
381
- // Set the listeningAddressIpv6 for the matter commissioning server
382
298
  if (hasParameter('ipv6address')) {
383
299
  this.ipv6address = getParameter('ipv6address');
384
300
  }
@@ -387,23 +303,17 @@ export class Matterbridge extends EventEmitter {
387
303
  if (this.ipv6address === '')
388
304
  this.ipv6address = undefined;
389
305
  }
390
- // Initialize PluginManager
391
306
  this.plugins = new PluginManager(this);
392
307
  await this.plugins.loadFromStorage();
393
- // Initialize DeviceManager
394
308
  this.devices = new DeviceManager(this, this.nodeContext);
395
- // Get the plugins from node storage and create the plugins node storage contexts
396
309
  for (const plugin of this.plugins) {
397
310
  const packageJson = await this.plugins.parse(plugin);
398
311
  if (packageJson === null && !hasParameter('add')) {
399
- // Try to reinstall the plugin from npm (for Docker pull and external plugins)
400
- // We don't do this when the add parameter is set because we shut down the process after adding the plugin
401
312
  this.log.info(`Error parsing plugin ${plg}${plugin.name}${nf}. Trying to reinstall it from npm.`);
402
313
  try {
403
314
  await this.spawnCommand('npm', ['install', '-g', plugin.name, '--omit=dev', '--verbose']);
404
315
  this.log.info(`Plugin ${plg}${plugin.name}${nf} reinstalled.`);
405
316
  plugin.error = false;
406
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
407
317
  }
408
318
  catch (error) {
409
319
  plugin.error = true;
@@ -420,7 +330,6 @@ export class Matterbridge extends EventEmitter {
420
330
  await plugin.nodeContext.set('description', plugin.description);
421
331
  await plugin.nodeContext.set('author', plugin.author);
422
332
  }
423
- // Log system info and create .matterbridge directory
424
333
  await this.logNodeAndSystemInfo();
425
334
  this.log.notice(`Matterbridge version ${this.matterbridgeVersion} ` +
426
335
  `${hasParameter('bridge') || (!hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'bridge') ? 'mode bridge ' : ''}` +
@@ -428,7 +337,6 @@ export class Matterbridge extends EventEmitter {
428
337
  `${hasParameter('controller') ? 'mode controller ' : ''}` +
429
338
  `${this.restartMode !== '' ? 'restart mode ' + this.restartMode + ' ' : ''}` +
430
339
  `running on ${this.systemInformation.osType} (v.${this.systemInformation.osRelease}) platform ${this.systemInformation.osPlatform} arch ${this.systemInformation.osArch}`);
431
- // Check node version and throw error
432
340
  const minNodeVersion = 18;
433
341
  const nodeVersion = process.versions.node;
434
342
  const versionMajor = parseInt(nodeVersion.split('.')[0]);
@@ -436,17 +344,10 @@ export class Matterbridge extends EventEmitter {
436
344
  this.log.error(`Node version ${versionMajor} is not supported. Please upgrade to ${minNodeVersion} or above.`);
437
345
  throw new Error(`Node version ${versionMajor} is not supported. Please upgrade to ${minNodeVersion} or above.`);
438
346
  }
439
- // Register process handlers
440
347
  this.registerProcessHandlers();
441
- // Parse command line
442
348
  await this.parseCommandLine();
443
349
  this.initialized = true;
444
350
  }
445
- /**
446
- * Parses the command line arguments and performs the corresponding actions.
447
- * @private
448
- * @returns {Promise<void>} A promise that resolves when the command line arguments have been processed, or the process exits.
449
- */
450
351
  async parseCommandLine() {
451
352
  if (hasParameter('help')) {
452
353
  this.log.info(`\nUsage: matterbridge [options]\n
@@ -554,14 +455,12 @@ export class Matterbridge extends EventEmitter {
554
455
  }
555
456
  if (hasParameter('factoryreset')) {
556
457
  try {
557
- // Delete matter storage file
558
458
  await fs.unlink(path.join(this.matterbridgeDirectory, this.matterStorageName));
559
459
  }
560
460
  catch (err) {
561
461
  this.log.error(`Error deleting storage: ${err}`);
562
462
  }
563
463
  try {
564
- // Delete node storage directory with its subdirectories
565
464
  await fs.rm(path.join(this.matterbridgeDirectory, this.nodeStorageName), { recursive: true });
566
465
  }
567
466
  catch (err) {
@@ -575,7 +474,6 @@ export class Matterbridge extends EventEmitter {
575
474
  this.emit('shutdown');
576
475
  return;
577
476
  }
578
- // Start the matter storage and create the matterbridge context
579
477
  try {
580
478
  await this.startMatterStorage('json', path.join(this.matterbridgeDirectory, this.matterStorageName));
581
479
  }
@@ -610,34 +508,28 @@ export class Matterbridge extends EventEmitter {
610
508
  this.emit('shutdown');
611
509
  return;
612
510
  }
613
- // Initialize frontend
614
511
  if (getIntParameter('frontend') !== 0 || getIntParameter('frontend') === undefined)
615
512
  await this.initializeFrontend(getIntParameter('frontend'));
616
- // Check each 60 minutes the latest versions
617
513
  this.checkUpdateInterval = setInterval(() => {
618
514
  this.getMatterbridgeLatestVersion();
619
515
  for (const plugin of this.plugins) {
620
516
  this.getPluginLatestVersion(plugin);
621
517
  }
622
518
  }, 60 * 60 * 1000);
623
- // Start the matterbridge in mode test
624
519
  if (hasParameter('test')) {
625
520
  this.bridgeMode = 'bridge';
626
521
  MatterbridgeDevice.bridgeMode = 'bridge';
627
522
  return;
628
523
  }
629
- // Start the matterbridge in mode controller
630
524
  if (hasParameter('controller')) {
631
525
  this.bridgeMode = 'controller';
632
526
  await this.startController();
633
527
  return;
634
528
  }
635
- // Check if the bridge mode is set and start matterbridge in bridge mode if not set
636
529
  if (!hasParameter('bridge') && !hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === '') {
637
530
  this.log.info('Setting default matterbridge start mode to bridge');
638
531
  await this.nodeContext?.set('bridgeMode', 'bridge');
639
532
  }
640
- // Start matterbridge in bridge mode
641
533
  if (hasParameter('bridge') || (!hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'bridge')) {
642
534
  this.bridgeMode = 'bridge';
643
535
  MatterbridgeDevice.bridgeMode = 'bridge';
@@ -646,7 +538,6 @@ export class Matterbridge extends EventEmitter {
646
538
  await this.startBridge();
647
539
  return;
648
540
  }
649
- // Start matterbridge in childbridge mode
650
541
  if (hasParameter('childbridge') || (!hasParameter('bridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'childbridge')) {
651
542
  this.bridgeMode = 'childbridge';
652
543
  MatterbridgeDevice.bridgeMode = 'childbridge';
@@ -656,28 +547,17 @@ export class Matterbridge extends EventEmitter {
656
547
  return;
657
548
  }
658
549
  }
659
- /**
660
- * Asynchronously loads and starts the registered plugins.
661
- *
662
- * This method is responsible for initializing and staarting all enabled plugins.
663
- * It ensures that each plugin is properly loaded and started before the ridge starts.
664
- *
665
- * @returns {Promise<void>} A promise that resolves when all plugins have been loaded and started.
666
- */
667
550
  async startPlugins() {
668
- // Check, load and start the plugins
669
551
  for (const plugin of this.plugins) {
670
552
  plugin.configJson = await this.plugins.loadConfig(plugin);
671
553
  plugin.schemaJson = await this.plugins.loadSchema(plugin);
672
- // Check if the plugin is available
673
554
  if (!(await this.plugins.resolve(plugin.path))) {
674
555
  this.log.error(`Plugin ${plg}${plugin.name}${er} not found or not validated. Disabling it.`);
675
556
  plugin.enabled = false;
676
557
  plugin.error = true;
677
558
  continue;
678
559
  }
679
- // Check if the plugin has a new version
680
- this.getPluginLatestVersion(plugin); // No await do it asyncronously
560
+ this.getPluginLatestVersion(plugin);
681
561
  if (!plugin.enabled) {
682
562
  this.log.info(`Plugin ${plg}${plugin.name}${nf} not enabled`);
683
563
  continue;
@@ -692,26 +572,20 @@ export class Matterbridge extends EventEmitter {
692
572
  plugin.addedDevices = undefined;
693
573
  plugin.qrPairingCode = undefined;
694
574
  plugin.manualPairingCode = undefined;
695
- this.plugins.load(plugin, true, 'Matterbridge is starting'); // No await do it asyncronously
575
+ this.plugins.load(plugin, true, 'Matterbridge is starting');
696
576
  }
697
577
  this.wssSendRefreshRequired();
698
578
  }
699
- /**
700
- * Registers the process handlers for uncaughtException, unhandledRejection, SIGINT and SIGTERM.
701
- * When either of these signals are received, the cleanup method is called with an appropriate message.
702
- */
703
579
  registerProcessHandlers() {
704
580
  this.log.debug(`Registering uncaughtException and unhandledRejection handlers...`);
705
581
  process.removeAllListeners('uncaughtException');
706
582
  process.removeAllListeners('unhandledRejection');
707
583
  this.exceptionHandler = async (error) => {
708
584
  this.log.fatal('Unhandled Exception detected at:', error.stack || error, rs);
709
- // await this.cleanup('Unhandled Exception detected, cleaning up...');
710
585
  };
711
586
  process.on('uncaughtException', this.exceptionHandler);
712
587
  this.rejectionHandler = async (reason, promise) => {
713
588
  this.log.fatal('Unhandled Rejection detected at:', promise, 'reason:', reason instanceof Error ? reason.stack : reason, rs);
714
- // await this.cleanup('Unhandled Rejection detected, cleaning up...');
715
589
  };
716
590
  process.on('unhandledRejection', this.rejectionHandler);
717
591
  this.log.debug(`Registering SIGINT and SIGTERM signal handlers...`);
@@ -724,9 +598,6 @@ export class Matterbridge extends EventEmitter {
724
598
  };
725
599
  process.on('SIGTERM', this.sigtermHandler);
726
600
  }
727
- /**
728
- * Deregisters the process uncaughtException, unhandledRejection, SIGINT and SIGTERM signal handlers.
729
- */
730
601
  deregisterProcesslHandlers() {
731
602
  this.log.debug(`Deregistering uncaughtException and unhandledRejection handlers...`);
732
603
  if (this.exceptionHandler)
@@ -743,11 +614,7 @@ export class Matterbridge extends EventEmitter {
743
614
  process.off('SIGTERM', this.sigtermHandler);
744
615
  this.sigtermHandler = undefined;
745
616
  }
746
- /**
747
- * Logs the node and system information.
748
- */
749
617
  async logNodeAndSystemInfo() {
750
- // IP address information
751
618
  const networkInterfaces = os.networkInterfaces();
752
619
  this.systemInformation.ipv4Address = '';
753
620
  this.systemInformation.ipv6Address = '';
@@ -767,7 +634,7 @@ export class Matterbridge extends EventEmitter {
767
634
  this.systemInformation.macAddress = detail.mac;
768
635
  }
769
636
  }
770
- if (this.systemInformation.ipv4Address !== '' /* && this.systemInformation.ipv6Address !== ''*/) {
637
+ if (this.systemInformation.ipv4Address !== '') {
771
638
  this.log.debug(`Using interface: '${this.systemInformation.interfaceName}'`);
772
639
  this.log.debug(`- with MAC address: '${this.systemInformation.macAddress}'`);
773
640
  this.log.debug(`- with IPv4 address: '${this.systemInformation.ipv4Address}'`);
@@ -775,22 +642,19 @@ export class Matterbridge extends EventEmitter {
775
642
  break;
776
643
  }
777
644
  }
778
- // Node information
779
645
  this.systemInformation.nodeVersion = process.versions.node;
780
646
  const versionMajor = parseInt(this.systemInformation.nodeVersion.split('.')[0]);
781
647
  const versionMinor = parseInt(this.systemInformation.nodeVersion.split('.')[1]);
782
648
  const versionPatch = parseInt(this.systemInformation.nodeVersion.split('.')[2]);
783
- // Host system information
784
649
  this.systemInformation.hostname = os.hostname();
785
650
  this.systemInformation.user = os.userInfo().username;
786
- this.systemInformation.osType = os.type(); // "Windows_NT", "Darwin", etc.
787
- this.systemInformation.osRelease = os.release(); // Kernel version
788
- this.systemInformation.osPlatform = os.platform(); // "win32", "linux", "darwin", etc.
789
- this.systemInformation.osArch = os.arch(); // "x64", "arm", etc.
790
- this.systemInformation.totalMemory = (os.totalmem() / 1024 / 1024 / 1024).toFixed(2) + ' GB'; // Convert to GB
791
- this.systemInformation.freeMemory = (os.freemem() / 1024 / 1024 / 1024).toFixed(2) + ' GB'; // Convert to GB
792
- this.systemInformation.systemUptime = (os.uptime() / 60 / 60).toFixed(2) + ' hours'; // Convert to hours
793
- // Log the system information
651
+ this.systemInformation.osType = os.type();
652
+ this.systemInformation.osRelease = os.release();
653
+ this.systemInformation.osPlatform = os.platform();
654
+ this.systemInformation.osArch = os.arch();
655
+ this.systemInformation.totalMemory = (os.totalmem() / 1024 / 1024 / 1024).toFixed(2) + ' GB';
656
+ this.systemInformation.freeMemory = (os.freemem() / 1024 / 1024 / 1024).toFixed(2) + ' GB';
657
+ this.systemInformation.systemUptime = (os.uptime() / 60 / 60).toFixed(2) + ' hours';
794
658
  this.log.debug('Host System Information:');
795
659
  this.log.debug(`- Hostname: ${this.systemInformation.hostname}`);
796
660
  this.log.debug(`- User: ${this.systemInformation.user}`);
@@ -806,19 +670,15 @@ export class Matterbridge extends EventEmitter {
806
670
  this.log.debug(`- Total Memory: ${this.systemInformation.totalMemory}`);
807
671
  this.log.debug(`- Free Memory: ${this.systemInformation.freeMemory}`);
808
672
  this.log.debug(`- System Uptime: ${this.systemInformation.systemUptime}`);
809
- // Home directory
810
673
  this.homeDirectory = getParameter('homedir') ?? os.homedir();
811
674
  this.matterbridgeInformation.homeDirectory = this.homeDirectory;
812
675
  this.log.debug(`Home Directory: ${this.homeDirectory}`);
813
- // Package root directory
814
676
  const currentFileDirectory = path.dirname(fileURLToPath(import.meta.url));
815
677
  this.rootDirectory = path.resolve(currentFileDirectory, '../');
816
678
  this.matterbridgeInformation.rootDirectory = this.rootDirectory;
817
679
  this.log.debug(`Root Directory: ${this.rootDirectory}`);
818
- // Global node_modules directory
819
680
  if (this.nodeContext)
820
681
  this.globalModulesDirectory = await this.nodeContext.get('globalModulesDirectory', '');
821
- // First run of Matterbridge so the node storage is empty
822
682
  if (this.globalModulesDirectory === '') {
823
683
  try {
824
684
  this.globalModulesDirectory = await this.getGlobalNodeModules();
@@ -842,7 +702,6 @@ export class Matterbridge extends EventEmitter {
842
702
  this.log.error(`Error getting global node_modules directory: ${error}`);
843
703
  });
844
704
  }
845
- // Create the data directory .matterbridge in the home directory
846
705
  this.matterbridgeDirectory = path.join(this.homeDirectory, '.matterbridge');
847
706
  this.matterbridgeInformation.matterbridgeDirectory = this.matterbridgeDirectory;
848
707
  try {
@@ -866,7 +725,6 @@ export class Matterbridge extends EventEmitter {
866
725
  }
867
726
  }
868
727
  this.log.debug(`Matterbridge Directory: ${this.matterbridgeDirectory}`);
869
- // Create the plugin directory Matterbridge in the home directory
870
728
  this.matterbridgePluginDirectory = path.join(this.homeDirectory, 'Matterbridge');
871
729
  this.matterbridgeInformation.matterbridgePluginDirectory = this.matterbridgePluginDirectory;
872
730
  try {
@@ -890,28 +748,19 @@ export class Matterbridge extends EventEmitter {
890
748
  }
891
749
  }
892
750
  this.log.debug(`Matterbridge Plugin Directory: ${this.matterbridgePluginDirectory}`);
893
- // Matterbridge version
894
751
  const packageJson = JSON.parse(await fs.readFile(path.join(this.rootDirectory, 'package.json'), 'utf-8'));
895
752
  this.matterbridgeVersion = packageJson.version;
896
753
  this.matterbridgeInformation.matterbridgeVersion = this.matterbridgeVersion;
897
754
  this.log.debug(`Matterbridge Version: ${this.matterbridgeVersion}`);
898
- // Matterbridge latest version
899
755
  if (this.nodeContext)
900
756
  this.matterbridgeLatestVersion = await this.nodeContext.get('matterbridgeLatestVersion', '');
901
757
  this.log.debug(`Matterbridge Latest Version: ${this.matterbridgeLatestVersion}`);
902
758
  this.getMatterbridgeLatestVersion();
903
- // Current working directory
904
759
  const currentDir = process.cwd();
905
760
  this.log.debug(`Current Working Directory: ${currentDir}`);
906
- // Command line arguments (excluding 'node' and the script name)
907
761
  const cmdArgs = process.argv.slice(2).join(' ');
908
762
  this.log.debug(`Command Line Arguments: ${cmdArgs}`);
909
763
  }
910
- /**
911
- * Retrieves the latest version of a package from the npm registry.
912
- * @param packageName - The name of the package.
913
- * @returns A Promise that resolves to the latest version of the package.
914
- */
915
764
  async getLatestVersion(packageName) {
916
765
  return new Promise((resolve, reject) => {
917
766
  this.execRunningCount++;
@@ -926,10 +775,6 @@ export class Matterbridge extends EventEmitter {
926
775
  });
927
776
  });
928
777
  }
929
- /**
930
- * Retrieves the path to the global Node.js modules directory.
931
- * @returns A promise that resolves to the path of the global Node.js modules directory.
932
- */
933
778
  async getGlobalNodeModules() {
934
779
  return new Promise((resolve, reject) => {
935
780
  this.execRunningCount++;
@@ -944,11 +789,6 @@ export class Matterbridge extends EventEmitter {
944
789
  });
945
790
  });
946
791
  }
947
- /**
948
- * Retrieves the latest version of Matterbridge and performs necessary actions based on the version comparison.
949
- * @private
950
- * @returns {Promise<void>} A promise that resolves when the latest version is retrieved and actions are performed.
951
- */
952
792
  async getMatterbridgeLatestVersion() {
953
793
  this.getLatestVersion('matterbridge')
954
794
  .then(async (matterbridgeLatestVersion) => {
@@ -965,19 +805,8 @@ export class Matterbridge extends EventEmitter {
965
805
  })
966
806
  .catch((error) => {
967
807
  this.log.error(`Error getting Matterbridge latest version: ${error.message}`);
968
- // error.stack && this.log.debug(error.stack);
969
808
  });
970
809
  }
971
- /**
972
- * Retrieves the latest version of a plugin and updates the plugin's latestVersion property.
973
- * If the plugin's version is different from the latest version, logs a warning message.
974
- * If the plugin's version is the same as the latest version, logs an info message.
975
- * If there is an error retrieving the latest version, logs an error message.
976
- *
977
- * @private
978
- * @param {RegisteredPlugin} plugin - The plugin for which to retrieve the latest version.
979
- * @returns {Promise<void>} A promise that resolves when the latest version is retrieved and actions are performed.
980
- */
981
810
  async getPluginLatestVersion(plugin) {
982
811
  this.getLatestVersion(plugin.name)
983
812
  .then(async (latestVersion) => {
@@ -989,54 +818,40 @@ export class Matterbridge extends EventEmitter {
989
818
  })
990
819
  .catch((error) => {
991
820
  this.log.error(`Error getting ${plg}${plugin.name}${er} latest version: ${error.message}`);
992
- // error.stack && this.log.debug(error.stack);
993
821
  });
994
822
  }
995
- /**
996
- * Creates a MatterLogger function to show the matter.js log messages in AnsiLogger (for the frontend).
997
- *
998
- * @returns {Function} The MatterLogger function.
999
- */
1000
823
  createMatterLogger() {
1001
- const matterLogger = new AnsiLogger({ logName: 'Matter', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: "debug" /* LogLevel.DEBUG */ });
824
+ const matterLogger = new AnsiLogger({ logName: 'Matter', logTimestampFormat: 4, logLevel: "debug" });
1002
825
  return (_level, formattedLog) => {
1003
826
  const logger = formattedLog.slice(44, 44 + 20).trim();
1004
827
  const message = formattedLog.slice(65);
1005
828
  matterLogger.logName = logger;
1006
829
  switch (_level) {
1007
830
  case MatterLogLevel.DEBUG:
1008
- matterLogger.log("debug" /* LogLevel.DEBUG */, message);
831
+ matterLogger.log("debug", message);
1009
832
  break;
1010
833
  case MatterLogLevel.INFO:
1011
- matterLogger.log("info" /* LogLevel.INFO */, message);
834
+ matterLogger.log("info", message);
1012
835
  break;
1013
836
  case MatterLogLevel.NOTICE:
1014
- matterLogger.log("notice" /* LogLevel.NOTICE */, message);
837
+ matterLogger.log("notice", message);
1015
838
  break;
1016
839
  case MatterLogLevel.WARN:
1017
- matterLogger.log("warn" /* LogLevel.WARN */, message);
840
+ matterLogger.log("warn", message);
1018
841
  break;
1019
842
  case MatterLogLevel.ERROR:
1020
- matterLogger.log("error" /* LogLevel.ERROR */, message);
843
+ matterLogger.log("error", message);
1021
844
  break;
1022
845
  case MatterLogLevel.FATAL:
1023
- matterLogger.log("fatal" /* LogLevel.FATAL */, message);
846
+ matterLogger.log("fatal", message);
1024
847
  break;
1025
848
  default:
1026
- matterLogger.log("debug" /* LogLevel.DEBUG */, message);
849
+ matterLogger.log("debug", message);
1027
850
  break;
1028
851
  }
1029
852
  };
1030
853
  }
1031
- /**
1032
- * Creates a Matter File Logger.
1033
- *
1034
- * @param {string} filePath - The path to the log file.
1035
- * @param {boolean} [unlink=false] - Whether to unlink the log file before creating a new one.
1036
- * @returns {Function} - A function that logs formatted messages to the log file.
1037
- */
1038
854
  async createMatterFileLogger(filePath, unlink = false) {
1039
- // 2024-08-21 08:55:19.488 DEBUG InteractionMessenger Sending DataReport chunk with 28 attributes and 0 events: 1004 bytes
1040
855
  let fileSize = 0;
1041
856
  if (unlink) {
1042
857
  try {
@@ -1085,83 +900,53 @@ export class Matterbridge extends EventEmitter {
1085
900
  }
1086
901
  };
1087
902
  }
1088
- /**
1089
- * Update matterbridge and cleanup.
1090
- */
1091
903
  async updateProcess() {
1092
904
  await this.cleanup('updating...', false);
1093
905
  }
1094
- /**
1095
- * Restarts the process by spawning a new process and exiting the current process.
1096
- */
1097
906
  async restartProcess() {
1098
907
  await this.cleanup('restarting...', true);
1099
908
  }
1100
- /**
1101
- * Shut down the process by exiting the current process.
1102
- */
1103
909
  async shutdownProcess() {
1104
910
  await this.cleanup('shutting down...', false);
1105
911
  }
1106
- /**
1107
- * Shut down the process and reset.
1108
- */
1109
912
  async unregisterAndShutdownProcess() {
1110
913
  this.log.info('Unregistering all devices and shutting down...');
1111
- for (const plugin of this.plugins /* .filter((plugin) => plugin.enabled && !plugin.error))*/) {
914
+ for (const plugin of this.plugins) {
1112
915
  await this.removeAllBridgedDevices(plugin.name);
1113
916
  }
1114
917
  await this.cleanup('unregistered all devices and shutting down...', false);
1115
918
  }
1116
- /**
1117
- * Shut down the process and reset.
1118
- */
1119
919
  async shutdownProcessAndReset() {
1120
920
  await this.cleanup('shutting down with reset...', false);
1121
921
  }
1122
- /**
1123
- * Shut down the process and factory reset.
1124
- */
1125
922
  async shutdownProcessAndFactoryReset() {
1126
923
  await this.cleanup('shutting down with factory reset...', false);
1127
924
  }
1128
- /**
1129
- * Cleans up the Matterbridge instance.
1130
- * @param message - The cleanup message.
1131
- * @param restart - Indicates whether to restart the instance after cleanup. Default is `false`.
1132
- * @returns A promise that resolves when the cleanup is completed.
1133
- */
1134
925
  async cleanup(message, restart = false) {
1135
926
  if (this.initialized && !this.hasCleanupStarted) {
1136
927
  this.hasCleanupStarted = true;
1137
928
  this.log.info(message);
1138
- // Deregisters the process handlers
1139
929
  this.deregisterProcesslHandlers();
1140
- // Clear the start matter interval
1141
930
  if (this.startMatterInterval) {
1142
931
  clearInterval(this.startMatterInterval);
1143
932
  this.startMatterInterval = undefined;
1144
933
  this.log.debug('Start matter interval cleared');
1145
934
  }
1146
- // Clear the check update interval
1147
935
  if (this.checkUpdateInterval) {
1148
936
  clearInterval(this.checkUpdateInterval);
1149
937
  this.checkUpdateInterval = undefined;
1150
938
  this.log.debug('Check update interval cleared');
1151
939
  }
1152
- // Clear the configure timeout
1153
940
  if (this.configureTimeout) {
1154
941
  clearTimeout(this.configureTimeout);
1155
942
  this.configureTimeout = undefined;
1156
943
  this.log.debug('Matterbridge configure timeout cleared');
1157
944
  }
1158
- // Clear the reachability timeout
1159
945
  if (this.reachabilityTimeout) {
1160
946
  clearTimeout(this.reachabilityTimeout);
1161
947
  this.reachabilityTimeout = undefined;
1162
948
  this.log.debug('Matterbridge reachability timeout cleared');
1163
949
  }
1164
- // Calling the shutdown method of each plugin and clear the reachability timeout
1165
950
  for (const plugin of this.plugins) {
1166
951
  if (!plugin.enabled || plugin.error)
1167
952
  continue;
@@ -1172,29 +957,24 @@ export class Matterbridge extends EventEmitter {
1172
957
  this.log.debug(`Plugin ${plg}${plugin.name}${db} reachability timeout cleared`);
1173
958
  }
1174
959
  }
1175
- // Close the http server
1176
960
  if (this.httpServer) {
1177
961
  this.httpServer.close();
1178
962
  this.httpServer.removeAllListeners();
1179
963
  this.httpServer = undefined;
1180
964
  this.log.debug('Frontend http server closed successfully');
1181
965
  }
1182
- // Close the https server
1183
966
  if (this.httpsServer) {
1184
967
  this.httpsServer.close();
1185
968
  this.httpsServer.removeAllListeners();
1186
969
  this.httpsServer = undefined;
1187
970
  this.log.debug('Frontend https server closed successfully');
1188
971
  }
1189
- // Remove listeners from the express app
1190
972
  if (this.expressApp) {
1191
973
  this.expressApp.removeAllListeners();
1192
974
  this.expressApp = undefined;
1193
975
  this.log.debug('Frontend app closed successfully');
1194
976
  }
1195
- // Close the WebSocket server
1196
977
  if (this.webSocketServer) {
1197
- // Close all active connections
1198
978
  this.webSocketServer.clients.forEach((client) => {
1199
979
  if (client.readyState === WebSocket.OPEN) {
1200
980
  client.close();
@@ -1210,39 +990,29 @@ export class Matterbridge extends EventEmitter {
1210
990
  });
1211
991
  this.webSocketServer = undefined;
1212
992
  }
1213
- // Convert the matter storage to the new format
1214
- if (hasParameter('convert') && this.edge === false && this.matterbridgeContext && ['updating...', 'restarting...', 'shutting down...'].includes(message)) {
993
+ if (!hasParameter('nostorageconversion') && this.edge === false && this.matterbridgeContext && ['updating...', 'restarting...', 'shutting down...'].includes(message)) {
1215
994
  await this.convertStorage(this.matterbridgeContext, 'Mattebridge');
1216
995
  }
1217
- // Closing matter
1218
996
  await this.stopMatterServer();
1219
- // Closing matter storage
1220
997
  await this.stopMatterStorage();
1221
- // Remove the matterfilelogger
1222
998
  try {
1223
999
  Logger.removeLogger('matterfilelogger');
1224
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1225
1000
  }
1226
1001
  catch (error) {
1227
- // this.log.debug(`Error removing the matterfilelogger for file ${CYAN}${path.join(this.matterbridgeDirectory, this.matterLoggerFile)}${er}: ${error instanceof Error ? error.message : error}`);
1228
1002
  }
1229
- // Serialize registeredDevices
1230
1003
  if (this.nodeStorage && this.nodeContext) {
1231
1004
  this.log.info('Saving registered devices...');
1232
1005
  const serializedRegisteredDevices = [];
1233
1006
  this.devices.forEach(async (device) => {
1234
1007
  const serializedMatterbridgeDevice = device.serialize();
1235
- // this.log.info(`- ${serializedMatterbridgeDevice.deviceName}${rs}\n`, serializedMatterbridgeDevice);
1236
1008
  if (serializedMatterbridgeDevice)
1237
1009
  serializedRegisteredDevices.push(serializedMatterbridgeDevice);
1238
1010
  });
1239
1011
  await this.nodeContext.set('devices', serializedRegisteredDevices);
1240
1012
  this.log.info(`Saved registered devices (${serializedRegisteredDevices?.length})`);
1241
- // Clear nodeContext and nodeStorage (they just need 1000ms to write the data to disk)
1242
1013
  this.log.debug(`Closing node storage context for ${plg}Matterbridge${db}...`);
1243
1014
  await this.nodeContext.close();
1244
1015
  this.nodeContext = undefined;
1245
- // Clear nodeContext for each plugin (they just need 1000ms to write the data to disk)
1246
1016
  for (const plugin of this.plugins) {
1247
1017
  if (plugin.nodeContext) {
1248
1018
  this.log.debug(`Closing node storage context for plugin ${plg}${plugin.name}${db}...`);
@@ -1273,16 +1043,13 @@ export class Matterbridge extends EventEmitter {
1273
1043
  }
1274
1044
  else {
1275
1045
  if (message === 'shutting down with reset...') {
1276
- // Delete matter storage file
1277
1046
  this.log.info('Resetting Matterbridge commissioning information...');
1278
1047
  await fs.unlink(path.join(this.matterbridgeDirectory, this.matterStorageName));
1279
1048
  this.log.info('Reset done! Remove all paired devices from the controllers.');
1280
1049
  }
1281
1050
  if (message === 'shutting down with factory reset...') {
1282
- // Delete matter storage file
1283
1051
  this.log.info('Resetting Matterbridge commissioning information...');
1284
1052
  await fs.unlink(path.join(this.matterbridgeDirectory, this.matterStorageName));
1285
- // Delete node storage directory with its subdirectories
1286
1053
  this.log.info('Resetting Matterbridge storage...');
1287
1054
  await fs.rm(path.join(this.matterbridgeDirectory, this.nodeStorageName), { recursive: true });
1288
1055
  this.log.info('Factory reset done! Remove all paired devices from the controllers.');
@@ -1295,33 +1062,19 @@ export class Matterbridge extends EventEmitter {
1295
1062
  this.initialized = false;
1296
1063
  }
1297
1064
  }
1298
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1299
1065
  async addBridgedEndpoint(pluginName, device) {
1300
- // Nothing to do here
1301
1066
  }
1302
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1303
1067
  async removeBridgedEndpoint(pluginName, device) {
1304
- // Nothing to do here
1305
1068
  }
1306
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1307
1069
  async removeAllBridgedEndpoints(pluginName) {
1308
- // Nothing to do here
1309
1070
  }
1310
- /**
1311
- * Adds a bridged device to the Matterbridge.
1312
- * @param pluginName - The name of the plugin.
1313
- * @param device - The bridged device to add.
1314
- * @returns {Promise<void>} - A promise that resolves when the device is added.
1315
- */
1316
1071
  async addBridgedDevice(pluginName, device) {
1317
1072
  this.log.debug(`Adding bridged device ${dev}${device.deviceName}${db} (${zb}${device.name}${db}) for plugin ${plg}${pluginName}${db}`);
1318
- // Check if the plugin is registered
1319
1073
  const plugin = this.plugins.get(pluginName);
1320
1074
  if (!plugin) {
1321
1075
  this.log.error(`Error adding bridged device ${dev}${device.deviceName}${er} (${zb}${device.name}${er}) plugin ${plg}${pluginName}${er} not found`);
1322
1076
  return;
1323
1077
  }
1324
- // Register and add the device to matterbridge aggregator in bridge mode
1325
1078
  if (this.bridgeMode === 'bridge') {
1326
1079
  if (!this.matterAggregator) {
1327
1080
  this.log.error(`Adding bridged device ${dev}${device.deviceName}${er} (${zb}${device.name}${er}) for plugin ${plg}${pluginName}${er} error: matterAggregator not found`);
@@ -1329,11 +1082,8 @@ export class Matterbridge extends EventEmitter {
1329
1082
  }
1330
1083
  this.matterAggregator.addBridgedDevice(device);
1331
1084
  }
1332
- // The first time create the commissioning server and the aggregator for DynamicPlatform
1333
- // Register and add the device in childbridge mode
1334
1085
  if (this.bridgeMode === 'childbridge') {
1335
1086
  if (plugin.type === 'AccessoryPlatform') {
1336
- // Check if the plugin is locked with the commissioning server
1337
1087
  if (!plugin.locked) {
1338
1088
  plugin.locked = true;
1339
1089
  plugin.storageContext = await this.importCommissioningServerContext(plugin.name, device);
@@ -1347,7 +1097,6 @@ export class Matterbridge extends EventEmitter {
1347
1097
  }
1348
1098
  }
1349
1099
  if (plugin.type === 'DynamicPlatform') {
1350
- // Check if the plugin is locked with the commissioning server and the aggregator
1351
1100
  if (!plugin.locked) {
1352
1101
  plugin.locked = true;
1353
1102
  this.log.debug(`Creating commissioning server context for ${plg}${plugin.name}${db}`);
@@ -1368,25 +1117,16 @@ export class Matterbridge extends EventEmitter {
1368
1117
  plugin.registeredDevices++;
1369
1118
  if (plugin.addedDevices !== undefined)
1370
1119
  plugin.addedDevices++;
1371
- // Add the device to the DeviceManager
1372
1120
  this.devices.set(device);
1373
1121
  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}`);
1374
1122
  }
1375
- /**
1376
- * Removes a bridged device from the Matterbridge.
1377
- * @param pluginName - The name of the plugin.
1378
- * @param device - The device to be removed.
1379
- * @returns A Promise that resolves when the device is successfully removed.
1380
- */
1381
1123
  async removeBridgedDevice(pluginName, device) {
1382
1124
  this.log.debug(`Removing bridged device ${dev}${device.deviceName}${db} (${zb}${device.name}${db}) for plugin ${plg}${pluginName}${db}`);
1383
- // Check if the plugin is registered
1384
1125
  const plugin = this.plugins.get(pluginName);
1385
1126
  if (!plugin) {
1386
1127
  this.log.error(`Error removing bridged device ${dev}${device.deviceName}${er} (${zb}${device.name}${er}) for plugin ${plg}${pluginName}${er}: plugin not found`);
1387
1128
  return;
1388
1129
  }
1389
- // Remove the device from matterbridge aggregator in bridge mode
1390
1130
  if (this.bridgeMode === 'bridge') {
1391
1131
  if (!this.matterAggregator) {
1392
1132
  this.log.error(`Error removing bridged device ${dev}${device.deviceName}${er} (${zb}${device.name}${er}) for plugin ${plg}${pluginName}${er}: matterAggregator not found`);
@@ -1396,8 +1136,6 @@ export class Matterbridge extends EventEmitter {
1396
1136
  device.setBridgedDeviceReachability(false);
1397
1137
  device.getClusterServerById(BridgedDeviceBasicInformation.Cluster.id)?.triggerReachableChangedEvent({ reachableNewValue: false });
1398
1138
  }
1399
- // device.getClusterServerById(BridgedDeviceBasicInformation.Cluster.id)?.triggerShutDownEvent({});
1400
- // device.getClusterServerById(BridgedDeviceBasicInformation.Cluster.id)?.triggerLeaveEvent({});
1401
1139
  this.matterAggregator?.removeBridgedDevice(device);
1402
1140
  this.log.info(`Removed bridged device(${plugin.registeredDevices}/${plugin.addedDevices}) ${dev}${device.deviceName}${nf} (${zb}${device.name}${nf}) for plugin ${plg}${pluginName}${nf}`);
1403
1141
  if (plugin.registeredDevices !== undefined)
@@ -1405,7 +1143,6 @@ export class Matterbridge extends EventEmitter {
1405
1143
  if (plugin.addedDevices !== undefined)
1406
1144
  plugin.addedDevices--;
1407
1145
  }
1408
- // Remove the device in childbridge mode
1409
1146
  if (this.bridgeMode === 'childbridge') {
1410
1147
  if (plugin.type === 'AccessoryPlatform') {
1411
1148
  if (!plugin.commissioningServer) {
@@ -1429,22 +1166,14 @@ export class Matterbridge extends EventEmitter {
1429
1166
  plugin.registeredDevices--;
1430
1167
  if (plugin.addedDevices !== undefined)
1431
1168
  plugin.addedDevices--;
1432
- // Remove the commissioning server
1433
1169
  if (plugin.registeredDevices === 0 && plugin.addedDevices === 0 && plugin.commissioningServer) {
1434
1170
  this.matterServer?.removeCommissioningServer(plugin.commissioningServer);
1435
1171
  plugin.commissioningServer = undefined;
1436
1172
  this.log.info(`Removed commissioning server for plugin ${plg}${pluginName}${nf}`);
1437
1173
  }
1438
1174
  }
1439
- // Remove the device from the DeviceManager
1440
1175
  this.devices.remove(device);
1441
1176
  }
1442
- /**
1443
- * Removes all bridged devices associated with a specific plugin.
1444
- *
1445
- * @param pluginName - The name of the plugin.
1446
- * @returns A promise that resolves when all devices have been removed.
1447
- */
1448
1177
  async removeAllBridgedDevices(pluginName) {
1449
1178
  this.log.debug(`Removing all bridged devices for plugin ${plg}${pluginName}${db}`);
1450
1179
  this.devices.forEach(async (device) => {
@@ -1453,13 +1182,7 @@ export class Matterbridge extends EventEmitter {
1453
1182
  }
1454
1183
  });
1455
1184
  }
1456
- /**
1457
- * Starts the Matterbridge in bridge mode.
1458
- * @private
1459
- * @returns {Promise<void>} A promise that resolves when the Matterbridge is started.
1460
- */
1461
1185
  async startBridge() {
1462
- // Plugins are configured by a timer when matter server is started and plugin.configured is set to true
1463
1186
  if (!this.storageManager)
1464
1187
  throw new Error('No storage manager initialized');
1465
1188
  if (!this.matterbridgeContext)
@@ -1478,7 +1201,6 @@ export class Matterbridge extends EventEmitter {
1478
1201
  let failCount = 0;
1479
1202
  this.startMatterInterval = setInterval(async () => {
1480
1203
  for (const plugin of this.plugins) {
1481
- // new code to not start the bridge if one plugin is in error cause the controllers will delete the devices loosing all the configuration
1482
1204
  if (!plugin.enabled)
1483
1205
  continue;
1484
1206
  if (plugin.error) {
@@ -1503,18 +1225,15 @@ export class Matterbridge extends EventEmitter {
1503
1225
  clearInterval(this.startMatterInterval);
1504
1226
  this.startMatterInterval = undefined;
1505
1227
  this.log.debug('Cleared startMatterInterval interval for Matterbridge');
1506
- // Start the Matter server
1507
1228
  await this.startMatterServer();
1508
1229
  this.log.notice('Matter server started');
1509
- // Show the QR code for commissioning or log the already commissioned message
1510
1230
  await this.showCommissioningQRCode(this.commissioningServer, this.matterbridgeContext, this.nodeContext, 'Matterbridge');
1511
- // Configure the plugins
1512
1231
  this.configureTimeout = setTimeout(async () => {
1513
1232
  for (const plugin of this.plugins) {
1514
1233
  if (!plugin.enabled || !plugin.loaded || !plugin.started || plugin.error)
1515
1234
  continue;
1516
1235
  try {
1517
- await this.plugins.configure(plugin); // TODO No await do it in parallel
1236
+ await this.plugins.configure(plugin);
1518
1237
  }
1519
1238
  catch (error) {
1520
1239
  plugin.error = true;
@@ -1523,7 +1242,6 @@ export class Matterbridge extends EventEmitter {
1523
1242
  }
1524
1243
  this.wssSendRefreshRequired();
1525
1244
  }, 30 * 1000);
1526
- // Setting reachability to true
1527
1245
  this.reachabilityTimeout = setTimeout(() => {
1528
1246
  this.log.info(`Setting reachability to true for ${plg}Matterbridge${db}`);
1529
1247
  if (this.commissioningServer)
@@ -1533,14 +1251,7 @@ export class Matterbridge extends EventEmitter {
1533
1251
  }, 60 * 1000);
1534
1252
  }, 1000);
1535
1253
  }
1536
- /**
1537
- * Starts the Matterbridge in childbridge mode.
1538
- * @private
1539
- * @returns {Promise<void>} A promise that resolves when the Matterbridge is started.
1540
- */
1541
1254
  async startChildbridge() {
1542
- // Matterbridge.addBridgedDevice creates the commissionig servers and add the devices to the the commissioning server or to the aggregator
1543
- // Plugins are configured by a timer when matter server is started and plugin.configured is set to true
1544
1255
  if (!this.storageManager)
1545
1256
  throw new Error('No storage manager initialized');
1546
1257
  this.matterServer = this.createMatterServer(this.storageManager);
@@ -1550,7 +1261,6 @@ export class Matterbridge extends EventEmitter {
1550
1261
  this.startMatterInterval = setInterval(async () => {
1551
1262
  let allStarted = true;
1552
1263
  for (const plugin of this.plugins) {
1553
- // new code to not start the bridge if one plugin is in error cause the controllers will delete the devices loosing all the configuration
1554
1264
  if (!plugin.enabled)
1555
1265
  continue;
1556
1266
  if (plugin.error) {
@@ -1578,16 +1288,14 @@ export class Matterbridge extends EventEmitter {
1578
1288
  clearInterval(this.startMatterInterval);
1579
1289
  this.startMatterInterval = undefined;
1580
1290
  this.log.debug('Cleared startMatterInterval interval in childbridge mode');
1581
- // Start the Matter server
1582
1291
  await this.startMatterServer();
1583
1292
  this.log.notice('Matter server started');
1584
- // Configure the plugins
1585
1293
  this.configureTimeout = setTimeout(async () => {
1586
1294
  for (const plugin of this.plugins) {
1587
1295
  if (!plugin.enabled || !plugin.loaded || !plugin.started || plugin.error)
1588
1296
  continue;
1589
1297
  try {
1590
- await this.plugins.configure(plugin); // TODO No await do it in parallel
1298
+ await this.plugins.configure(plugin);
1591
1299
  }
1592
1300
  catch (error) {
1593
1301
  plugin.error = true;
@@ -1616,7 +1324,6 @@ export class Matterbridge extends EventEmitter {
1616
1324
  continue;
1617
1325
  }
1618
1326
  await this.showCommissioningQRCode(plugin.commissioningServer, plugin.storageContext, plugin.nodeContext, plugin.name);
1619
- // Setting reachability to true
1620
1327
  plugin.reachabilityTimeout = setTimeout(() => {
1621
1328
  this.log.info(`Setting reachability to true for ${plg}${plugin.name}${db}`);
1622
1329
  if (plugin.commissioningServer)
@@ -1629,11 +1336,6 @@ export class Matterbridge extends EventEmitter {
1629
1336
  }
1630
1337
  }, 1000);
1631
1338
  }
1632
- /**
1633
- * Starts the Matterbridge controller.
1634
- * @private
1635
- * @returns {Promise<void>} A promise that resolves when the Matterbridge is started.
1636
- */
1637
1339
  async startController() {
1638
1340
  if (!this.storageManager) {
1639
1341
  this.log.error('No storage manager initialized');
@@ -1696,7 +1398,7 @@ export class Matterbridge extends EventEmitter {
1696
1398
  const nodeId = await this.commissioningController.commissionNode(options);
1697
1399
  this.log.info(`Commissioning successfully done with nodeId: ${nodeId}`);
1698
1400
  this.log.info('ActiveSessionInformation:', this.commissioningController.getActiveSessionInformation());
1699
- } // (hasParameter('pairingcode'))
1401
+ }
1700
1402
  if (hasParameter('unpairall')) {
1701
1403
  this.log.info('***Commissioning controller unpairing all nodes...');
1702
1404
  const nodeIds = this.commissioningController.getCommissionedNodes();
@@ -1707,8 +1409,6 @@ export class Matterbridge extends EventEmitter {
1707
1409
  return;
1708
1410
  }
1709
1411
  if (hasParameter('discover')) {
1710
- // const discover = await this.commissioningController.discoverCommissionableDevices({ productId: 0x8000, deviceType: 0xfff1 });
1711
- // console.log(discover);
1712
1412
  }
1713
1413
  if (!this.commissioningController.isCommissioned()) {
1714
1414
  this.log.info('***Commissioning controller is not commissioned: use matterbridge -controller -pairingcode [pairingcode] to commission a device');
@@ -1749,12 +1449,10 @@ export class Matterbridge extends EventEmitter {
1749
1449
  },
1750
1450
  });
1751
1451
  node.logStructure();
1752
- // Get the interaction client
1753
1452
  this.log.info('Getting the interaction client');
1754
1453
  const interactionClient = await node.getInteractionClient();
1755
1454
  let cluster;
1756
1455
  let attributes;
1757
- // Log BasicInformationCluster
1758
1456
  cluster = BasicInformationCluster;
1759
1457
  attributes = await interactionClient.getMultipleAttributes({
1760
1458
  attributes: [{ clusterId: cluster.id }],
@@ -1764,7 +1462,6 @@ export class Matterbridge extends EventEmitter {
1764
1462
  attributes.forEach((attribute) => {
1765
1463
  this.log.info(`- endpoint ${or}${attribute.path.endpointId}${nf} cluster ${hk}${getClusterNameById(attribute.path.clusterId)}${nf} (${hk}0x${attribute.path.clusterId.toString(16)}${nf}) attribute ${zb}${attribute.path.attributeName}${nf} (${zb}0x${attribute.path.attributeId.toString(16)}${nf}): ${typeof attribute.value === 'object' ? stringify(attribute.value) : attribute.value}`);
1766
1464
  });
1767
- // Log PowerSourceCluster
1768
1465
  cluster = PowerSourceCluster;
1769
1466
  attributes = await interactionClient.getMultipleAttributes({
1770
1467
  attributes: [{ clusterId: cluster.id }],
@@ -1774,7 +1471,6 @@ export class Matterbridge extends EventEmitter {
1774
1471
  attributes.forEach((attribute) => {
1775
1472
  this.log.info(`- endpoint ${or}${attribute.path.endpointId}${nf} cluster ${hk}${getClusterNameById(attribute.path.clusterId)}${nf} (${hk}0x${attribute.path.clusterId.toString(16)}${nf}) attribute ${zb}${attribute.path.attributeName}${nf} (${zb}0x${attribute.path.attributeId.toString(16)}${nf}): ${typeof attribute.value === 'object' ? stringify(attribute.value) : attribute.value}`);
1776
1473
  });
1777
- // Log ThreadNetworkDiagnostics
1778
1474
  cluster = ThreadNetworkDiagnosticsCluster;
1779
1475
  attributes = await interactionClient.getMultipleAttributes({
1780
1476
  attributes: [{ clusterId: cluster.id }],
@@ -1784,7 +1480,6 @@ export class Matterbridge extends EventEmitter {
1784
1480
  attributes.forEach((attribute) => {
1785
1481
  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}`);
1786
1482
  });
1787
- // Log SwitchCluster
1788
1483
  cluster = SwitchCluster;
1789
1484
  attributes = await interactionClient.getMultipleAttributes({
1790
1485
  attributes: [{ clusterId: cluster.id }],
@@ -1805,15 +1500,6 @@ export class Matterbridge extends EventEmitter {
1805
1500
  this.log.info('Subscribed to all attributes and events');
1806
1501
  }
1807
1502
  }
1808
- /** ***********************************************************************************************************************************/
1809
- /** Matter.js methods */
1810
- /** ***********************************************************************************************************************************/
1811
- /**
1812
- * Starts the matter storage process based on the specified storage type and name.
1813
- * @param {string} storageType - The type of storage to start (e.g., 'disk', 'json').
1814
- * @param {string} storageName - The name of the storage file.
1815
- * @returns {Promise<void>} - A promise that resolves when the storage process is started.
1816
- */
1817
1503
  async startMatterStorage(storageType, storageName) {
1818
1504
  this.log.debug(`Starting matter ${storageType} storage ${CYAN}${storageName}${db}`);
1819
1505
  if (storageType === 'disk') {
@@ -1862,166 +1548,136 @@ export class Matterbridge extends EventEmitter {
1862
1548
  await this.matterbridgeContext.set('passcode', this.passcode);
1863
1549
  await this.matterbridgeContext.set('discriminator', this.discriminator);
1864
1550
  }
1865
- /**
1866
- * Convert the old API matter storage to the new API format.
1867
- * @param {StorageContext} context - The context of Matterbridge or of the plugin.
1868
- * @param {string} pluginName - The name of the plugin or Matterbridge.
1869
- * @returns {Promise<void>} - A promise that resolves when the storage process is started.
1870
- */
1871
1551
  async convertStorage(context, pluginName) {
1872
- const storageService = Environment.default.get(StorageService);
1873
- Environment.default.vars.set('path.root', path.join(this.matterbridgeDirectory, 'matterstorage' + (this.profile ? '.' + this.profile : '')));
1874
- const nodeStorage = await storageService.open('Matterbridge');
1875
- if ((await nodeStorage.createContext('persist').get('converted', false)) === true) {
1876
- this.log.info(`Matter node storage already converted to Matterbridge edge for ${plg}${pluginName}${nf}`);
1877
- return;
1878
- }
1879
- else {
1880
- this.log.notice(`Converting matter node storage to Matterbridge edge for ${plg}${pluginName}${nt}...`);
1881
- }
1882
- // Read FabricManager from the old storage and get FabricManager.fabrics and FabricManager.nextFabricIndex
1883
- const fabricManagerContext = context.createContext('FabricManager');
1884
- const fabrics = (await fabricManagerContext.get('fabrics', []));
1885
- const nextFabricIndex = await fabricManagerContext.get('nextFabricIndex', 1);
1886
- // Read EventHandler from the old storage
1887
- const eventHandlerContext = context.createContext('EventHandler');
1888
- // Read SessionManager from the old storage
1889
- const sessionManagerContext = context.createContext('SessionManager');
1890
- // Read EndpointStructure from the old storage
1891
- const endpointStructureContext = context.createContext('EndpointStructure');
1892
- // Read generalCommissioning from the old storage
1893
- const generalCommissioningContext = context.createContext('Cluster-0-48');
1894
- // Read basicInformation from the old storage
1895
- const basicInformationContext = context.createContext('Cluster-0-40');
1896
- const fabricInfo = {};
1897
- const fabricInfoArray = [];
1898
- const nocArray = [];
1899
- const trcArray = [];
1900
- const aclArray = [];
1901
- this.log.info(`Found ${CYAN}${fabrics.length}${nf} fabrics (nextFabricIndex ${CYAN}${nextFabricIndex}${nf}) for ${plg}${pluginName}${nf}:`);
1902
- for (const fabric of fabrics) {
1903
- this.log.info(`- fabricIndex ${CYAN}${fabric.fabricIndex}${nf} fabricId ${CYAN}${fabric.fabricId}${nf} nodeId ${CYAN}${fabric.nodeId}${nf} rootNodeId ${CYAN}${fabric.rootNodeId}${nf} rootVendorId ${CYAN}${fabric.rootVendorId}${nf} label ${CYAN}${fabric.label}${nf}`);
1904
- fabricInfo[fabric.fabricIndex] = {
1905
- fabricIndex: fabric.fabricIndex,
1906
- fabricId: fabric.fabricId,
1907
- nodeId: fabric.nodeId,
1908
- rootNodeId: fabric.rootNodeId,
1909
- rootVendorId: fabric.rootVendorId,
1910
- label: fabric.label,
1911
- };
1912
- fabricInfoArray.push({
1913
- fabricIndex: fabric.fabricIndex,
1914
- fabricId: fabric.fabricId,
1915
- nodeId: fabric.nodeId,
1916
- vendorId: fabric.rootVendorId,
1917
- rootPublicKey: fabric.rootPublicKey,
1918
- label: fabric.label,
1919
- });
1920
- nocArray.push({ noc: fabric.operationalCert, icac: null, fabricIndex: fabric.fabricIndex });
1921
- // eslint-disable-next-line no-useless-escape
1922
- trcArray.push('{\"__object__\":\"Uint8Array\",\"__value__\":\"' + Buffer.from(fabric.rootCert).toString('hex') + '\"}');
1923
- // eslint-disable-next-line no-useless-escape
1924
- aclArray.push({ fabricIndex: fabric.fabricIndex, privilege: 5, authMode: 2, subjects: ['{\"__object__\":\"BigInt\",\"__value__\":\"' + fabric.rootNodeId.toString().replace('n', '') + '\"}'], targets: null });
1925
- // this.log.debug(`- fabricinfo ${fabric.fabricIndex}`, fabricInfo[fabric.fabricIndex]);
1926
- }
1927
- await nodeStorage.createContext('fabrics').set('fabrics', fabrics);
1928
- await nodeStorage.createContext('fabrics').set('nextFabricIndex', nextFabricIndex);
1929
- await nodeStorage.createContext('sessions').set('resumptionRecords', await sessionManagerContext.get('resumptionRecords', []));
1930
- await nodeStorage.createContext('events').set('lastEventNumber', await eventHandlerContext.get('lastEventNumber', 1));
1931
- await nodeStorage.createContext('root').set('__number__', 0);
1932
- await nodeStorage.createContext('root').createContext('parts').createContext('Matterbridge').set('__number__', 1);
1933
- await nodeStorage.createContext('root').createContext('commissioning').set('enabled', true);
1934
- await nodeStorage.createContext('root').createContext('commissioning').set('commissioned', true);
1935
- await nodeStorage.createContext('root').createContext('commissioning').set('fabrics', fabricInfo);
1936
- await nodeStorage.createContext('root').createContext('operationalCredentials').set('commissionedFabrics', fabricInfoArray.length);
1937
- await nodeStorage.createContext('root').createContext('operationalCredentials').set('fabrics', fabricInfoArray);
1938
- // operationalCredentials.nocs ==>> [{noc: fabric.operationalCert, icac: null, fabricIndex: fabric.fabricIndex }]
1939
- await nodeStorage.createContext('root').createContext('operationalCredentials').set('nocs', nocArray);
1940
- // operationalCredentials.trustedRootCertificates ==>> ["{\"__object__\":\"Uint8Array\",\"__value__\":\"" + fabric.rootCert + "\"}"]
1941
- await nodeStorage.createContext('root').createContext('operationalCredentials').set('trustedRootCertificates', trcArray);
1942
- // ACL updated, updating ACL manager { fabricIndex: 3, privilege: 5, authMode: 2, subjects: [ 18446744060825763897 ], targets: null }
1943
- // From fabric.rootNodeId
1944
- // [{"fabricIndex":3,"privilege":5,"authMode":2,"subjects":["{\"__object__\":\"BigInt\",\"__value__\":\"18446744060825763897\"}"],"targets":null}]
1945
- await nodeStorage.createContext('root').createContext('accessControl').set('acl', aclArray);
1946
- await nodeStorage
1947
- .createContext('root')
1948
- .createContext('generalCommissioning')
1949
- .set('breadcrumb', await generalCommissioningContext.get('breadcrumb', BigInt(0)));
1950
- await nodeStorage
1951
- .createContext('root')
1952
- .createContext('basicInformation')
1953
- .set('location', await basicInformationContext.get('location', 'XX'));
1954
- await nodeStorage.createContext('root').createContext('network').set('ble', false);
1955
- await nodeStorage.createContext('root').createContext('network').set('operationalPort', 5540);
1956
- await nodeStorage.createContext('root').createContext('productDescription').set('productId', 0x8000);
1957
- await nodeStorage.createContext('root').createContext('productDescription').set('vendorId', 0xfff1);
1958
- /*
1959
- "Matterbridge.EndpointStructure": {
1960
- "unique_d60ca095a002f160-index_0": 1,
1961
- "unique_d60ca095a002f160-index_0-custom_Switch0": 2,
1962
- "unique_d60ca095a002f160-index_0-custom_Outlet0": 3,
1963
- "unique_d60ca095a002f160-index_0-custom_Light0": 4,
1964
- "unique_d60ca095a002f160-index_0-unique_7ddb4752b982ee108d5928e934f0fcfa": 2,
1965
- "unique_d60ca095a002f160-index_0-unique_7ddb4752b982ee108d5928e934f0fcfa-custom_PowerSource": 3,
1966
- "unique_d60ca095a002f160-index_0-unique_7ddb4752b982ee108d5928e934f0fcfa-custom_light:0": 4,
1967
- "unique_d60ca095a002f160-index_0-unique_7ddb4752b982ee108d5928e934f0fcfa-custom_light:1": 5,
1968
- "unique_d60ca095a002f160-index_0-unique_7ddb4752b982ee108d5928e934f0fcfa-custom_light:2": 6,
1969
- "unique_d60ca095a002f160-index_0-unique_7ddb4752b982ee108d5928e934f0fcfa-custom_light:3": 7,
1970
- "unique_d60ca095a002f160-index_0-unique_7ddb4752b982ee108d5928e934f0fcfa-custom_meter:0": 8,
1971
- "unique_d60ca095a002f160-index_0-unique_7ddb4752b982ee108d5928e934f0fcfa-custom_meter:1": 9,
1972
- "unique_d60ca095a002f160-index_0-unique_7ddb4752b982ee108d5928e934f0fcfa-custom_meter:2": 10,
1973
- "unique_d60ca095a002f160-index_0-unique_7ddb4752b982ee108d5928e934f0fcfa-custom_meter:3": 11,
1974
- "nextEndpointId": 5
1975
- },
1976
- */
1977
- for (const key of await endpointStructureContext.keys()) {
1978
- if (key === 'nextEndpointId') {
1979
- await nodeStorage.createContext('root').set('__nextNumber__', await endpointStructureContext.get(key));
1980
- continue;
1552
+ try {
1553
+ const storageService = Environment.default.get(StorageService);
1554
+ Environment.default.vars.set('path.root', path.join(this.matterbridgeDirectory, 'matterstorage' + (this.profile ? '.' + this.profile : '')));
1555
+ const nodeStorage = await storageService.open('Matterbridge');
1556
+ if ((await nodeStorage.createContext('root').createContext('generalDiagnostics').get('rebootCount', 0)) > 0) {
1557
+ this.log.info(`Matter node storage already converted to Matterbridge edge for ${plg}${pluginName}${nf}`);
1558
+ return;
1981
1559
  }
1982
- const parts = key.split('-');
1983
- const number = await endpointStructureContext.get(key);
1984
- // this.log.debug(`- endpointStructure key ${key} value ${number}`);
1985
- if (parts.length === 2) {
1986
- this.log.debug(`Converting Matterbridge.EndpointStructure:${key}:${number} to root.parts.Matterbridge.__number__:${number}`);
1987
- await nodeStorage.createContext('root').createContext('parts').createContext('Matterbridge').set('__number__', number);
1988
- }
1989
- else if (parts.length === 3 && parts[2].startsWith('custom_')) {
1990
- this.log.debug(`Converting Matterbridge.EndpointStructure:${key}:${number} to root.parts.Matterbridge.parts.${parts[2].replace('custom_', '')}.__number__:${number}`);
1991
- await nodeStorage.createContext('root').createContext('parts').createContext('Matterbridge').createContext('parts').createContext(parts[2].replace('custom_', '')).set('__number__', number);
1992
- }
1993
- else if (parts.length === 3 && parts[2].startsWith('unique_')) {
1994
- const device = this.devices.get(parts[2].replace('unique_', ''));
1995
- if (device && device.deviceName && device.maybeNumber) {
1996
- this.log.debug(`Converting Matterbridge.EndpointStructure:${key}:${number} to root.parts.Matterbridge.parts.${device.deviceName.replace(/[ .]/g, '')}.__number__:${device.maybeNumber}`);
1997
- await nodeStorage.createContext('root').createContext('parts').createContext('Matterbridge').createContext('parts').createContext(device.deviceName.replace(/[ .]/g, '')).set('__number__', device.maybeNumber);
1998
- }
1999
- }
2000
- }
2001
- await nodeStorage.createContext('persist').set('converted', true);
2002
- await nodeStorage.createContext('persist').set('deviceName', await context.get('deviceName'));
2003
- await nodeStorage.createContext('persist').set('deviceType', await context.get('deviceType'));
2004
- await nodeStorage.createContext('persist').set('vendorId', await context.get('vendorId'));
2005
- await nodeStorage.createContext('persist').set('vendorName', await context.get('vendorName'));
2006
- await nodeStorage.createContext('persist').set('productId', await context.get('productId'));
2007
- await nodeStorage.createContext('persist').set('productName', await context.get('productName'));
2008
- await nodeStorage.createContext('persist').set('nodeLabel', await context.get('nodeLabel'));
2009
- await nodeStorage.createContext('persist').set('productLabel', await context.get('productLabel'));
2010
- await nodeStorage.createContext('persist').set('serialNumber', 'SN' + (await context.get('serialNumber')));
2011
- await nodeStorage.createContext('persist').set('uniqueId', 'UI' + (await context.get('uniqueId')));
2012
- await nodeStorage.createContext('persist').set('softwareVersion', await context.get('softwareVersion'));
2013
- await nodeStorage.createContext('persist').set('softwareVersionString', await context.get('softwareVersionString'));
2014
- await nodeStorage.createContext('persist').set('hardwareVersion', await context.get('hardwareVersion'));
2015
- await nodeStorage.createContext('persist').set('hardwareVersionString', await context.get('hardwareVersionString'));
2016
- await context.set('converted', true);
2017
- this.log.notice(`Matter storage converted to Matterbridge edge for ${plg}${pluginName}${nt}`);
1560
+ else {
1561
+ this.log.notice(`Converting matter node storage to Matterbridge edge for ${plg}${pluginName}${nt}...`);
1562
+ }
1563
+ const fabricManagerContext = context.createContext('FabricManager');
1564
+ const fabrics = (await fabricManagerContext.get('fabrics', []));
1565
+ const nextFabricIndex = await fabricManagerContext.get('nextFabricIndex', 1);
1566
+ const eventHandlerContext = context.createContext('EventHandler');
1567
+ const sessionManagerContext = context.createContext('SessionManager');
1568
+ const endpointStructureContext = context.createContext('EndpointStructure');
1569
+ const generalCommissioningContext = context.createContext('Cluster-0-48');
1570
+ const basicInformationContext = context.createContext('Cluster-0-40');
1571
+ const fabricInfo = {};
1572
+ const fabricInfoArray = [];
1573
+ const nocArray = [];
1574
+ const trcArray = [];
1575
+ const aclArray = [];
1576
+ this.log.info(`Found ${CYAN}${fabrics.length}${nf} fabrics (nextFabricIndex ${CYAN}${nextFabricIndex}${nf}) for ${plg}${pluginName}${nf}:`);
1577
+ for (const fabric of fabrics) {
1578
+ this.log.info(`- fabricIndex ${CYAN}${fabric.fabricIndex}${nf} fabricId ${CYAN}${fabric.fabricId}${nf} nodeId ${CYAN}${fabric.nodeId}${nf} rootNodeId ${CYAN}${fabric.rootNodeId}${nf} rootVendorId ${CYAN}${fabric.rootVendorId}${nf} label ${CYAN}${fabric.label}${nf}`);
1579
+ fabricInfo[fabric.fabricIndex] = {
1580
+ fabricIndex: fabric.fabricIndex,
1581
+ fabricId: fabric.fabricId,
1582
+ nodeId: fabric.nodeId,
1583
+ rootNodeId: fabric.rootNodeId,
1584
+ rootVendorId: fabric.rootVendorId,
1585
+ label: fabric.label,
1586
+ };
1587
+ fabricInfoArray.push({
1588
+ fabricIndex: fabric.fabricIndex,
1589
+ fabricId: fabric.fabricId,
1590
+ nodeId: fabric.nodeId,
1591
+ vendorId: fabric.rootVendorId,
1592
+ rootPublicKey: fabric.rootPublicKey,
1593
+ label: fabric.label,
1594
+ });
1595
+ nocArray.push({ noc: fabric.operationalCert, icac: null, fabricIndex: fabric.fabricIndex });
1596
+ trcArray.push('{\"__object__\":\"Uint8Array\",\"__value__\":\"' + Buffer.from(fabric.rootCert).toString('hex') + '\"}');
1597
+ this.log.info(`- updating ACL for fabricIndex ${fabric.fabricIndex}:`, fabric.scopedClusterData);
1598
+ const acl = fabric.scopedClusterData.get(0x1f)?.get('acl');
1599
+ if (acl && acl.value.length > 0) {
1600
+ aclArray.push(acl.value[0]);
1601
+ this.log.info(`- ACL updated to ${debugStringify(acl.value)}${nf} for fabricIndex ${CYAN}${fabric.fabricIndex}${nf}`);
1602
+ }
1603
+ else {
1604
+ const defaultAcl = { fabricIndex: fabric.fabricIndex, privilege: 5, authMode: 2, subjects: [fabric.rootNodeId], targets: null };
1605
+ aclArray.push(defaultAcl);
1606
+ this.log.info(`- ACL updated to default ${debugStringify(defaultAcl)}${nf} for fabricIndex ${CYAN}${fabric.fabricIndex}${nf}`);
1607
+ }
1608
+ }
1609
+ await nodeStorage.createContext('fabrics').set('fabrics', fabrics);
1610
+ await nodeStorage.createContext('fabrics').set('nextFabricIndex', nextFabricIndex);
1611
+ await nodeStorage.createContext('sessions').set('resumptionRecords', await sessionManagerContext.get('resumptionRecords', []));
1612
+ await nodeStorage.createContext('events').set('lastEventNumber', await eventHandlerContext.get('lastEventNumber', 1));
1613
+ await nodeStorage.createContext('root').set('__number__', 0);
1614
+ await nodeStorage.createContext('root').createContext('parts').createContext('Matterbridge').set('__number__', 1);
1615
+ await nodeStorage.createContext('root').createContext('commissioning').set('enabled', true);
1616
+ await nodeStorage.createContext('root').createContext('commissioning').set('commissioned', true);
1617
+ await nodeStorage.createContext('root').createContext('commissioning').set('fabrics', fabricInfo);
1618
+ await nodeStorage.createContext('root').createContext('operationalCredentials').set('commissionedFabrics', fabricInfoArray.length);
1619
+ await nodeStorage.createContext('root').createContext('operationalCredentials').set('fabrics', fabricInfoArray);
1620
+ await nodeStorage.createContext('root').createContext('operationalCredentials').set('nocs', nocArray);
1621
+ await nodeStorage.createContext('root').createContext('operationalCredentials').set('trustedRootCertificates', trcArray);
1622
+ await nodeStorage.createContext('root').createContext('accessControl').set('acl', aclArray);
1623
+ await nodeStorage
1624
+ .createContext('root')
1625
+ .createContext('generalCommissioning')
1626
+ .set('breadcrumb', await generalCommissioningContext.get('breadcrumb', BigInt(0)));
1627
+ await nodeStorage
1628
+ .createContext('root')
1629
+ .createContext('basicInformation')
1630
+ .set('location', await basicInformationContext.get('location', 'XX'));
1631
+ await nodeStorage.createContext('root').createContext('network').set('ble', false);
1632
+ await nodeStorage.createContext('root').createContext('network').set('operationalPort', 5540);
1633
+ await nodeStorage.createContext('root').createContext('productDescription').set('productId', 0x8000);
1634
+ await nodeStorage.createContext('root').createContext('productDescription').set('vendorId', 0xfff1);
1635
+ for (const key of await endpointStructureContext.keys()) {
1636
+ if (key === 'nextEndpointId') {
1637
+ await nodeStorage.createContext('root').set('__nextNumber__', await endpointStructureContext.get(key));
1638
+ continue;
1639
+ }
1640
+ const parts = key.split('-');
1641
+ const number = await endpointStructureContext.get(key);
1642
+ if (parts.length === 2) {
1643
+ this.log.debug(`Converting Matterbridge.EndpointStructure:${key}:${number} to root.parts.Matterbridge.__number__:${number}`);
1644
+ await nodeStorage.createContext('root').createContext('parts').createContext('Matterbridge').set('__number__', number);
1645
+ }
1646
+ else if (parts.length === 3 && parts[2].startsWith('custom_')) {
1647
+ this.log.debug(`Converting Matterbridge.EndpointStructure:${key}:${number} to root.parts.Matterbridge.parts.${parts[2].replace('custom_', '')}.__number__:${number}`);
1648
+ await nodeStorage.createContext('root').createContext('parts').createContext('Matterbridge').createContext('parts').createContext(parts[2].replace('custom_', '')).set('__number__', number);
1649
+ }
1650
+ else if (parts.length === 3 && parts[2].startsWith('unique_')) {
1651
+ const device = this.devices.get(parts[2].replace('unique_', ''));
1652
+ if (device && device.deviceName && device.maybeNumber) {
1653
+ this.log.debug(`Converting Matterbridge.EndpointStructure:${key}:${number} to root.parts.Matterbridge.parts.${device.deviceName.replace(/[ .]/g, '')}.__number__:${device.maybeNumber}`);
1654
+ await nodeStorage.createContext('root').createContext('parts').createContext('Matterbridge').createContext('parts').createContext(device.deviceName.replace(/[ .]/g, '')).set('__number__', device.maybeNumber);
1655
+ }
1656
+ }
1657
+ }
1658
+ await nodeStorage.createContext('persist').set('converted', true);
1659
+ await nodeStorage.createContext('persist').set('deviceName', await context.get('deviceName'));
1660
+ await nodeStorage.createContext('persist').set('deviceType', await context.get('deviceType'));
1661
+ await nodeStorage.createContext('persist').set('vendorId', await context.get('vendorId'));
1662
+ await nodeStorage.createContext('persist').set('vendorName', await context.get('vendorName'));
1663
+ await nodeStorage.createContext('persist').set('productId', await context.get('productId'));
1664
+ await nodeStorage.createContext('persist').set('productName', await context.get('productName'));
1665
+ await nodeStorage.createContext('persist').set('nodeLabel', await context.get('nodeLabel'));
1666
+ await nodeStorage.createContext('persist').set('productLabel', await context.get('productLabel'));
1667
+ await nodeStorage.createContext('persist').set('serialNumber', 'SN' + (await context.get('serialNumber')));
1668
+ await nodeStorage.createContext('persist').set('uniqueId', await context.get('uniqueId'));
1669
+ await nodeStorage.createContext('persist').set('softwareVersion', await context.get('softwareVersion'));
1670
+ await nodeStorage.createContext('persist').set('softwareVersionString', await context.get('softwareVersionString'));
1671
+ await nodeStorage.createContext('persist').set('hardwareVersion', await context.get('hardwareVersion'));
1672
+ await nodeStorage.createContext('persist').set('hardwareVersionString', await context.get('hardwareVersionString'));
1673
+ await context.set('converted', true);
1674
+ this.log.notice(`Matter storage converted to Matterbridge edge for ${plg}${pluginName}${nt}`);
1675
+ this.log.notice(`If you want to try out matterbridge edge (beta) add -edge to the command line.`);
1676
+ }
1677
+ catch (error) {
1678
+ this.log.error(`convertStorage error converting matter storage to Matterbridge edge for ${plg}${pluginName}${er}:`, error);
1679
+ }
2018
1680
  }
2019
- /**
2020
- * Makes a backup copy of the specified matter JSON storage file.
2021
- *
2022
- * @param storageName - The name of the JSON storage file to be backed up.
2023
- * @param backupName - The name of the backup file to be created.
2024
- */
2025
1681
  async backupMatterStorage(storageName, backupName) {
2026
1682
  try {
2027
1683
  this.log.debug(`Making backup copy of ${storageName}`);
@@ -2042,12 +1698,6 @@ export class Matterbridge extends EventEmitter {
2042
1698
  }
2043
1699
  }
2044
1700
  }
2045
- /**
2046
- * Restore the specified matter JSON storage file.
2047
- *
2048
- * @param backupName - The name of the backup file to restore from.
2049
- * @param storageName - The name of the JSON storage file to restored.
2050
- */
2051
1701
  async restoreMatterStorage(backupName, storageName) {
2052
1702
  try {
2053
1703
  this.log.notice(`Restoring the backup copy of ${storageName}`);
@@ -2068,10 +1718,6 @@ export class Matterbridge extends EventEmitter {
2068
1718
  }
2069
1719
  }
2070
1720
  }
2071
- /**
2072
- * Stops the matter storage.
2073
- * @returns {Promise<void>} A promise that resolves when the storage is stopped.
2074
- */
2075
1721
  async stopMatterStorage() {
2076
1722
  this.log.debug('Stopping storage');
2077
1723
  await this.storageManager?.close();
@@ -2080,14 +1726,8 @@ export class Matterbridge extends EventEmitter {
2080
1726
  this.matterbridgeContext = undefined;
2081
1727
  this.mattercontrollerContext = undefined;
2082
1728
  }
2083
- /**
2084
- * Creates a Matter server using the provided storage manager and the provided mdnsInterface.
2085
- * @param storageManager The storage manager to be used by the Matter server.
2086
- *
2087
- */
2088
1729
  createMatterServer(storageManager) {
2089
1730
  this.log.debug('Creating matter server');
2090
- // Validate mdnsInterface
2091
1731
  if (this.mdnsInterface) {
2092
1732
  const networkInterfaces = os.networkInterfaces();
2093
1733
  const availableInterfaces = Object.keys(networkInterfaces);
@@ -2103,10 +1743,6 @@ export class Matterbridge extends EventEmitter {
2103
1743
  this.log.debug(`Created matter server with mdnsInterface: ${this.mdnsInterface ?? 'all available interfaces'}`);
2104
1744
  return matterServer;
2105
1745
  }
2106
- /**
2107
- * Starts the Matter server.
2108
- * If the Matter server is not initialized, it logs an error and performs cleanup.
2109
- */
2110
1746
  async startMatterServer() {
2111
1747
  if (!this.matterServer) {
2112
1748
  this.log.error('No matter server initialized');
@@ -2116,11 +1752,7 @@ export class Matterbridge extends EventEmitter {
2116
1752
  this.log.debug('Starting matter server...');
2117
1753
  await this.matterServer.start();
2118
1754
  this.log.debug('Started matter server');
2119
- // this.commissioningServer?.getRootEndpoint() && logEndpoint(this.commissioningServer?.getRootEndpoint());
2120
1755
  }
2121
- /**
2122
- * Stops the Matter server, commissioningServer and commissioningController.
2123
- */
2124
1756
  async stopMatterServer() {
2125
1757
  this.log.debug('Stopping matter commissioningServer');
2126
1758
  await this.commissioningServer?.close();
@@ -2134,35 +1766,23 @@ export class Matterbridge extends EventEmitter {
2134
1766
  this.matterAggregator = undefined;
2135
1767
  this.matterServer = undefined;
2136
1768
  }
2137
- /**
2138
- * Creates a Matter Aggregator.
2139
- * @param {StorageContext} context - The storage context.
2140
- * @returns {Aggregator} - The created Matter Aggregator.
2141
- */
2142
1769
  async createMatterAggregator(context, pluginName) {
2143
1770
  this.log.debug(`Creating matter aggregator for ${plg}${pluginName}${db}`);
2144
1771
  const matterAggregator = new Aggregator();
2145
1772
  return matterAggregator;
2146
1773
  }
2147
- /**
2148
- * Creates a matter commissioning server.
2149
- *
2150
- * @param {StorageContext} context - The storage context.
2151
- * @param {string} pluginName - The name of the commissioning server.
2152
- * @returns {CommissioningServer} The created commissioning server.
2153
- */
2154
1774
  async createCommisioningServer(context, pluginName) {
2155
1775
  this.log.debug(`Creating matter commissioning server for plugin ${plg}${pluginName}${db}`);
2156
1776
  const deviceName = await context.get('deviceName');
2157
1777
  const deviceType = await context.get('deviceType');
2158
1778
  const vendorId = await context.get('vendorId');
2159
- const vendorName = await context.get('vendorName'); // Home app = Manufacturer
1779
+ const vendorName = await context.get('vendorName');
2160
1780
  const productId = await context.get('productId');
2161
- const productName = await context.get('productName'); // Home app = Model
1781
+ const productName = await context.get('productName');
2162
1782
  const serialNumber = await context.get('serialNumber');
2163
1783
  const uniqueId = await context.get('uniqueId');
2164
1784
  const softwareVersion = await context.get('softwareVersion', 1);
2165
- const softwareVersionString = await context.get('softwareVersionString', '1.0.0'); // Home app = Firmware Revision
1785
+ const softwareVersionString = await context.get('softwareVersionString', '1.0.0');
2166
1786
  const hardwareVersion = await context.get('hardwareVersion', 1);
2167
1787
  const hardwareVersionString = await context.get('hardwareVersionString', '1.0.0');
2168
1788
  this.log.debug(`Creating matter commissioning server for plugin ${plg}${pluginName}${db} with deviceName '${deviceName}' deviceType ${deviceType}(0x${deviceType.toString(16).padStart(4, '0')})`);
@@ -2170,7 +1790,6 @@ export class Matterbridge extends EventEmitter {
2170
1790
  this.log.debug(`Creating matter commissioning server for plugin ${plg}${pluginName}${db} with softwareVersion ${softwareVersion} softwareVersionString ${softwareVersionString}`);
2171
1791
  this.log.debug(`Creating matter commissioning server for plugin ${plg}${pluginName}${db} with hardwareVersion ${hardwareVersion} hardwareVersionString ${hardwareVersionString}`);
2172
1792
  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} `);
2173
- // Validate ipv4address
2174
1793
  if (this.ipv4address) {
2175
1794
  const networkInterfaces = os.networkInterfaces();
2176
1795
  const availableAddresses = Object.values(networkInterfaces)
@@ -2185,7 +1804,6 @@ export class Matterbridge extends EventEmitter {
2185
1804
  this.log.info(`Using ipv4address '${this.ipv4address}' for the Matter commissioning server.`);
2186
1805
  }
2187
1806
  }
2188
- // Validate ipv6address
2189
1807
  if (this.ipv6address) {
2190
1808
  const networkInterfaces = os.networkInterfaces();
2191
1809
  const availableAddresses = Object.values(networkInterfaces)
@@ -2216,7 +1834,7 @@ export class Matterbridge extends EventEmitter {
2216
1834
  nodeLabel: productName,
2217
1835
  productLabel: productName,
2218
1836
  softwareVersion,
2219
- softwareVersionString, // Home app = Firmware Revision
1837
+ softwareVersionString,
2220
1838
  hardwareVersion,
2221
1839
  hardwareVersionString,
2222
1840
  uniqueId,
@@ -2312,24 +1930,6 @@ export class Matterbridge extends EventEmitter {
2312
1930
  commissioningServer.addCommandHandler('testEventTrigger', async ({ request: { enableKey, eventTrigger } }) => this.log.info(`testEventTrigger called on GeneralDiagnostic cluster: ${enableKey} ${eventTrigger}`));
2313
1931
  return commissioningServer;
2314
1932
  }
2315
- /**
2316
- * Creates a commissioning server storage context.
2317
- *
2318
- * @param pluginName - The name of the plugin.
2319
- * @param deviceName - The name of the device.
2320
- * @param deviceType - The type of the device.
2321
- * @param vendorId - The vendor ID.
2322
- * @param vendorName - The vendor name.
2323
- * @param productId - The product ID.
2324
- * @param productName - The product name.
2325
- * @param serialNumber - The serial number of the device (optional).
2326
- * @param uniqueId - The unique ID of the device (optional).
2327
- * @param softwareVersion - The software version of the device (optional).
2328
- * @param softwareVersionString - The software version string of the device (optional).
2329
- * @param hardwareVersion - The hardware version of the device (optional).
2330
- * @param hardwareVersionString - The hardware version string of the device (optional).
2331
- * @returns The storage context for the commissioning server.
2332
- */
2333
1933
  async createCommissioningServerContext(pluginName, deviceName, deviceType, vendorId, vendorName, productId, productName) {
2334
1934
  if (!this.storageManager)
2335
1935
  throw new Error('No storage manager initialized');
@@ -2357,13 +1957,6 @@ export class Matterbridge extends EventEmitter {
2357
1957
  this.log.debug(`- hardwareVersion: ${await storageContext.get('hardwareVersion')} hardwareVersionString: ${await storageContext.get('hardwareVersionString')}`);
2358
1958
  return storageContext;
2359
1959
  }
2360
- /**
2361
- * Imports the commissioning server context for a specific plugin and device.
2362
- * @param pluginName - The name of the plugin.
2363
- * @param device - The MatterbridgeDevice object representing the device.
2364
- * @returns The commissioning server context.
2365
- * @throws Error if the BasicInformationCluster is not found.
2366
- */
2367
1960
  async importCommissioningServerContext(pluginName, device) {
2368
1961
  this.log.debug(`Importing matter commissioning server storage context from device for ${plg}${pluginName}${db}`);
2369
1962
  const basic = device.getClusterServer(BasicInformationCluster);
@@ -2398,14 +1991,6 @@ export class Matterbridge extends EventEmitter {
2398
1991
  this.log.debug(`- hardwareVersion: ${await storageContext.get('hardwareVersion')} hardwareVersionString: ${await storageContext.get('hardwareVersionString')}`);
2399
1992
  return storageContext;
2400
1993
  }
2401
- /**
2402
- * Shows the commissioning server QR code for a given plugin.
2403
- * @param {CommissioningServer} commissioningServer - The commissioning server instance.
2404
- * @param {StorageContext} storageContext - The storage context instance.
2405
- * @param {NodeStorage} nodeContext - The node storage instance.
2406
- * @param {string} pluginName - The name of the plugin of Matterbridge in bridge mode.
2407
- * @returns {Promise<void>} - A promise that resolves when the QR code is shown.
2408
- */
2409
1994
  async showCommissioningQRCode(commissioningServer, storageContext, nodeContext, pluginName) {
2410
1995
  if (!commissioningServer || !storageContext || !nodeContext || !pluginName) {
2411
1996
  this.log.error(`showCommissioningQRCode error: commissioningServer: ${!commissioningServer} storageContext: ${!storageContext} nodeContext: ${!nodeContext} pluginName: ${pluginName}`);
@@ -2416,8 +2001,7 @@ export class Matterbridge extends EventEmitter {
2416
2001
  const { qrPairingCode, manualPairingCode } = commissioningServer.getPairingCode();
2417
2002
  const QrCode = new QrCodeSchema();
2418
2003
  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`);
2419
- // eslint-disable-next-line no-console
2420
- if (this.log.logLevel === "debug" /* LogLevel.DEBUG */ || this.log.logLevel === "info" /* LogLevel.INFO */)
2004
+ if (this.log.logLevel === "debug" || this.log.logLevel === "info")
2421
2005
  console.log(`${QrCode.encode(qrPairingCode)}\n`);
2422
2006
  this.log.info(`${plg}${pluginName}${nf} \n\nqrPairingCode: ${qrPairingCode} \n\nManual pairing code: ${manualPairingCode}\n`);
2423
2007
  if (pluginName === 'Matterbridge') {
@@ -2464,12 +2048,6 @@ export class Matterbridge extends EventEmitter {
2464
2048
  }
2465
2049
  this.wssSendRefreshRequired();
2466
2050
  }
2467
- /**
2468
- * Sanitizes the fabric information by converting bigint properties to string cause res.json doesn't know bigint.
2469
- *
2470
- * @param fabricInfo - The array of exposed fabric information objects.
2471
- * @returns An array of sanitized exposed fabric information objects.
2472
- */
2473
2051
  sanitizeFabricInformations(fabricInfo) {
2474
2052
  return fabricInfo.map((info) => {
2475
2053
  return {
@@ -2483,12 +2061,6 @@ export class Matterbridge extends EventEmitter {
2483
2061
  };
2484
2062
  });
2485
2063
  }
2486
- /**
2487
- * Sanitizes the session information by converting bigint properties to string.
2488
- *
2489
- * @param sessionInfo - The array of session information objects.
2490
- * @returns An array of sanitized session information objects.
2491
- */
2492
2064
  sanitizeSessionInformation(sessionInfo) {
2493
2065
  return sessionInfo
2494
2066
  .filter((session) => session.isPeerActive)
@@ -2516,12 +2088,6 @@ export class Matterbridge extends EventEmitter {
2516
2088
  };
2517
2089
  });
2518
2090
  }
2519
- /**
2520
- * Sets the reachability of a commissioning server and trigger.
2521
- *
2522
- * @param {CommissioningServer} commissioningServer - The commissioning server to set the reachability for.
2523
- * @param {boolean} reachable - The new reachability status.
2524
- */
2525
2091
  setCommissioningServerReachability(commissioningServer, reachable) {
2526
2092
  const basicInformationCluster = commissioningServer?.getRootClusterServer(BasicInformationCluster);
2527
2093
  if (basicInformationCluster && basicInformationCluster.attributes.reachable !== undefined)
@@ -2529,11 +2095,6 @@ export class Matterbridge extends EventEmitter {
2529
2095
  if (basicInformationCluster && basicInformationCluster.triggerReachableChangedEvent)
2530
2096
  basicInformationCluster.triggerReachableChangedEvent({ reachableNewValue: reachable });
2531
2097
  }
2532
- /**
2533
- * Sets the reachability of the specified matter aggregator and its bridged devices and trigger.
2534
- * @param {Aggregator} matterAggregator - The matter aggregator to set the reachability for.
2535
- * @param {boolean} reachable - A boolean indicating the reachability status to set.
2536
- */
2537
2098
  setAggregatorReachability(matterAggregator, reachable) {
2538
2099
  const basicInformationCluster = matterAggregator.getClusterServer(BasicInformationCluster);
2539
2100
  if (basicInformationCluster && basicInformationCluster.attributes.reachable !== undefined)
@@ -2546,12 +2107,6 @@ export class Matterbridge extends EventEmitter {
2546
2107
  device.getClusterServer(BridgedDeviceBasicInformationCluster)?.triggerReachableChangedEvent({ reachableNewValue: reachable });
2547
2108
  });
2548
2109
  }
2549
- /**
2550
- * Sets the reachability of a device and trigger.
2551
- *
2552
- * @param {MatterbridgeDevice} device - The device to set the reachability for.
2553
- * @param {boolean} reachable - The new reachability status of the device.
2554
- */
2555
2110
  setDeviceReachability(device, reachable) {
2556
2111
  const basicInformationCluster = device.getClusterServer(BasicInformationCluster);
2557
2112
  if (basicInformationCluster && basicInformationCluster.attributes.reachable !== undefined)
@@ -2600,10 +2155,6 @@ export class Matterbridge extends EventEmitter {
2600
2155
  }
2601
2156
  return vendorName;
2602
2157
  };
2603
- /**
2604
- * Retrieves the base registered plugins sanitized for res.json().
2605
- * @returns {BaseRegisteredPlugin[]} A promise that resolves to an array of BaseRegisteredPlugin objects.
2606
- */
2607
2158
  async getBaseRegisteredPlugins() {
2608
2159
  const baseRegisteredPlugins = [];
2609
2160
  for (const plugin of this.plugins) {
@@ -2635,36 +2186,13 @@ export class Matterbridge extends EventEmitter {
2635
2186
  }
2636
2187
  return baseRegisteredPlugins;
2637
2188
  }
2638
- /**
2639
- * Spawns a child process with the given command and arguments.
2640
- * @param {string} command - The command to execute.
2641
- * @param {string[]} args - The arguments to pass to the command (default: []).
2642
- * @returns {Promise<boolean>} A promise that resolves when the child process exits successfully, or rejects if there is an error.
2643
- */
2644
2189
  async spawnCommand(command, args = []) {
2645
- /*
2646
- npm > npm.cmd on windows
2647
- cmd.exe ['dir'] on windows
2648
- await this.spawnCommand('npm', ['install', '-g', 'matterbridge']);
2649
- process.on('unhandledRejection', (reason, promise) => {
2650
- this.log.error('Unhandled Rejection at:', promise, 'reason:', reason);
2651
- });
2652
-
2653
- spawn - [14:27:21.125] [Matterbridge:spawn]: changed 38 packages in 4s
2654
- spawn - [14:27:21.125] [Matterbridge:spawn]: 10 packages are looking for funding run `npm fund` for details
2655
- debug - [14:27:21.131] [Matterbridge]: Child process exited with code 0 and signal null
2656
- debug - [14:27:21.131] [Matterbridge]: Child process stdio streams have closed with code 0
2657
- */
2658
2190
  const cmdLine = command + ' ' + args.join(' ');
2659
2191
  if (process.platform === 'win32' && command === 'npm') {
2660
- // Must be spawn('cmd.exe', ['/c', 'npm -g install <package>']);
2661
2192
  const argstring = 'npm ' + args.join(' ');
2662
2193
  args.splice(0, args.length, '/c', argstring);
2663
2194
  command = 'cmd.exe';
2664
2195
  }
2665
- // Decide when using sudo on linux
2666
- // When you need sudo: Spawn stderr: npm error Error: EACCES: permission denied
2667
- // When you don't need sudo: Failed to start child process "npm install -g matterbridge-eve-door": spawn sudo ENOENT
2668
2196
  if (hasParameter('sudo') || (process.platform === 'linux' && command === 'npm' && !hasParameter('docker') && !hasParameter('nosudo'))) {
2669
2197
  args.unshift(command);
2670
2198
  command = 'sudo';
@@ -2722,102 +2250,55 @@ export class Matterbridge extends EventEmitter {
2722
2250
  }
2723
2251
  });
2724
2252
  }
2725
- /**
2726
- * Sends a WebSocket message to all connected clients.
2727
- *
2728
- * @param {string} level - The logger level of the message: debug info notice warn error fatal...
2729
- * @param {string} time - The time string of the message
2730
- * @param {string} name - The logger name of the message
2731
- * @param {string} message - The content of the message.
2732
- */
2733
2253
  wssSendMessage(level, time, name, message) {
2734
2254
  if (!level || !time || !name || !message)
2735
2255
  return;
2736
- // Remove ANSI escape codes from the message
2737
- // eslint-disable-next-line no-control-regex
2738
2256
  message = message.replace(/\x1B\[[0-9;]*[m|s|u|K]/g, '');
2739
- // Remove leading asterisks from the message
2740
2257
  message = message.replace(/^\*+/, '');
2741
- // Replace all occurrences of \t and \n
2742
2258
  message = message.replace(/[\t\n]/g, '');
2743
- // Remove non-printable characters
2744
- // eslint-disable-next-line no-control-regex
2745
2259
  message = message.replace(/[\x00-\x1F\x7F]/g, '');
2746
- // Replace all occurrences of \" with "
2747
2260
  message = message.replace(/\\"/g, '"');
2748
- // Define the maximum allowed length for continuous characters without a space
2749
2261
  const maxContinuousLength = 100;
2750
2262
  const keepStartLength = 20;
2751
2263
  const keepEndLength = 20;
2752
- // Split the message into words
2753
2264
  message = message
2754
2265
  .split(' ')
2755
2266
  .map((word) => {
2756
- // If the word length exceeds the max continuous length, insert spaces and truncate
2757
2267
  if (word.length > maxContinuousLength) {
2758
2268
  return word.slice(0, keepStartLength) + ' ... ' + word.slice(-keepEndLength);
2759
2269
  }
2760
2270
  return word;
2761
2271
  })
2762
2272
  .join(' ');
2763
- // Send the message to all connected clients
2764
2273
  this.webSocketServer?.clients.forEach((client) => {
2765
2274
  if (client.readyState === WebSocket.OPEN) {
2766
2275
  client.send(JSON.stringify({ id: WS_ID_LOG, src: 'Matterbridge', level, time, name, message }));
2767
2276
  }
2768
2277
  });
2769
2278
  }
2770
- /**
2771
- * Sends a need to refresh WebSocket message to all connected clients.
2772
- *
2773
- */
2774
2279
  wssSendRefreshRequired() {
2775
2280
  this.matterbridgeInformation.refreshRequired = true;
2776
- // Send the message to all connected clients
2777
2281
  this.webSocketServer?.clients.forEach((client) => {
2778
2282
  if (client.readyState === WebSocket.OPEN) {
2779
2283
  client.send(JSON.stringify({ id: WS_ID_REFRESH_NEEDED, src: 'Matterbridge', dst: 'Matterbridge', method: 'refresh_required', params: {} }));
2780
2284
  }
2781
2285
  });
2782
2286
  }
2783
- /**
2784
- * Sends a need to restart WebSocket message to all connected clients.
2785
- *
2786
- */
2787
2287
  wssSendRestartRequired() {
2788
2288
  this.matterbridgeInformation.restartRequired = true;
2789
- // Send the message to all connected clients
2790
2289
  this.webSocketServer?.clients.forEach((client) => {
2791
2290
  if (client.readyState === WebSocket.OPEN) {
2792
2291
  client.send(JSON.stringify({ id: WS_ID_RESTART_NEEDED, src: 'Matterbridge', dst: 'Matterbridge', method: 'restart_required', params: {} }));
2793
2292
  }
2794
2293
  });
2795
2294
  }
2796
- /**
2797
- * Initializes the frontend of Matterbridge.
2798
- *
2799
- * @param port The port number to run the frontend server on. Default is 8283.
2800
- */
2801
2295
  async initializeFrontend(port = 8283) {
2802
2296
  let initializeError = false;
2803
2297
  this.log.debug(`Initializing the frontend ${hasParameter('ssl') ? 'https' : 'http'} server on port ${YELLOW}${port}${db}`);
2804
- // Create the express app that serves the frontend
2805
2298
  this.expressApp = express();
2806
- // Log all requests to the server for debugging
2807
- /*
2808
- if (hasParameter('homedir')) {
2809
- this.expressApp.use((req, res, next) => {
2810
- this.log.debug(`Received request on expressApp: ${req.method} ${req.url}`);
2811
- next();
2812
- });
2813
- }
2814
- */
2815
- // Serve static files from '/static' endpoint
2816
2299
  this.expressApp.use(express.static(path.join(this.rootDirectory, 'frontend/build')));
2817
2300
  if (!hasParameter('ssl')) {
2818
- // Create an HTTP server and attach the express app
2819
2301
  this.httpServer = createServer(this.expressApp);
2820
- // Listen on the specified port
2821
2302
  if (hasParameter('ingress')) {
2822
2303
  this.httpServer.listen(port, '0.0.0.0', () => {
2823
2304
  this.log.info(`The frontend http server is listening on ${UNDERLINE}http://0.0.0.0:${port}${UNDERLINEOFF}${rs}`);
@@ -2831,7 +2312,6 @@ export class Matterbridge extends EventEmitter {
2831
2312
  this.log.info(`The frontend http server is listening on ${UNDERLINE}http://[${this.systemInformation.ipv6Address}]:${port}${UNDERLINEOFF}${rs}`);
2832
2313
  });
2833
2314
  }
2834
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
2835
2315
  this.httpServer.on('error', (error) => {
2836
2316
  this.log.error(`Frontend http server error listening on ${port}`);
2837
2317
  switch (error.code) {
@@ -2847,7 +2327,6 @@ export class Matterbridge extends EventEmitter {
2847
2327
  });
2848
2328
  }
2849
2329
  else {
2850
- // Load the SSL certificate, the private key and optionally the CA certificate
2851
2330
  let cert;
2852
2331
  try {
2853
2332
  cert = await fs.readFile(path.join(this.matterbridgeDirectory, 'certs/cert.pem'), 'utf8');
@@ -2875,9 +2354,7 @@ export class Matterbridge extends EventEmitter {
2875
2354
  this.log.info(`CA certificate file ${path.join(this.matterbridgeDirectory, 'certs/ca.pem')} not loaded: ${error}`);
2876
2355
  }
2877
2356
  const serverOptions = { cert, key, ca };
2878
- // Create an HTTPS server with the SSL certificate and private key (ca is optional) and attach the express app
2879
2357
  this.httpsServer = https.createServer(serverOptions, this.expressApp);
2880
- // Listen on the specified port
2881
2358
  if (hasParameter('ingress')) {
2882
2359
  this.httpsServer.listen(port, '0.0.0.0', () => {
2883
2360
  this.log.info(`The frontend https server is listening on ${UNDERLINE}https://0.0.0.0:${port}${UNDERLINEOFF}${rs}`);
@@ -2891,7 +2368,6 @@ export class Matterbridge extends EventEmitter {
2891
2368
  this.log.info(`The frontend https server is listening on ${UNDERLINE}https://[${this.systemInformation.ipv6Address}]:${port}${UNDERLINEOFF}${rs}`);
2892
2369
  });
2893
2370
  }
2894
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
2895
2371
  this.httpsServer.on('error', (error) => {
2896
2372
  this.log.error(`Frontend https server error listening on ${port}`);
2897
2373
  switch (error.code) {
@@ -2908,13 +2384,12 @@ export class Matterbridge extends EventEmitter {
2908
2384
  }
2909
2385
  if (initializeError)
2910
2386
  return;
2911
- // Createe a WebSocket server and attach it to the http or https server
2912
2387
  const wssPort = port;
2913
2388
  const wssHost = hasParameter('ssl') ? `wss://${this.systemInformation.ipv4Address}:${wssPort}` : `ws://${this.systemInformation.ipv4Address}:${wssPort}`;
2914
2389
  this.webSocketServer = new WebSocketServer(hasParameter('ssl') ? { server: this.httpsServer } : { server: this.httpServer });
2915
2390
  this.webSocketServer.on('connection', (ws, request) => {
2916
2391
  const clientIp = request.socket.remoteAddress;
2917
- AnsiLogger.setGlobalCallback(this.wssSendMessage.bind(this), "debug" /* LogLevel.DEBUG */);
2392
+ AnsiLogger.setGlobalCallback(this.wssSendMessage.bind(this), "debug");
2918
2393
  this.log.info(`WebSocketServer client "${clientIp}" connected to Matterbridge`);
2919
2394
  ws.on('message', (message) => {
2920
2395
  this.log.debug(`WebSocket client message: ${message}`);
@@ -2947,7 +2422,6 @@ export class Matterbridge extends EventEmitter {
2947
2422
  this.webSocketServer.on('error', (ws, error) => {
2948
2423
  this.log.error(`WebSocketServer error: ${error}`);
2949
2424
  });
2950
- // Endpoint to validate login code
2951
2425
  this.expressApp.post('/api/login', express.json(), async (req, res) => {
2952
2426
  const { password } = req.body;
2953
2427
  this.log.debug('The frontend sent /api/login', password);
@@ -2966,14 +2440,12 @@ export class Matterbridge extends EventEmitter {
2966
2440
  this.log.warn('/api/login error wrong password');
2967
2441
  res.json({ valid: false });
2968
2442
  }
2969
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
2970
2443
  }
2971
2444
  catch (error) {
2972
2445
  this.log.error('/api/login error getting password');
2973
2446
  res.json({ valid: false });
2974
2447
  }
2975
2448
  });
2976
- // Endpoint to provide settings
2977
2449
  this.expressApp.get('/api/settings', express.json(), async (req, res) => {
2978
2450
  this.log.debug('The frontend sent /api/settings');
2979
2451
  this.matterbridgeInformation.bridgeMode = this.bridgeMode;
@@ -2994,17 +2466,13 @@ export class Matterbridge extends EventEmitter {
2994
2466
  this.matterbridgeInformation.matterbridgeSessionInformations = Array.from(this.matterbridgeSessionInformations.values());
2995
2467
  this.matterbridgeInformation.profile = this.profile;
2996
2468
  const response = { wssHost, ssl: hasParameter('ssl'), systemInformation: this.systemInformation, matterbridgeInformation: this.matterbridgeInformation };
2997
- // this.log.debug('Response:', debugStringify(response));
2998
2469
  res.json(response);
2999
2470
  });
3000
- // Endpoint to provide plugins
3001
2471
  this.expressApp.get('/api/plugins', async (req, res) => {
3002
2472
  this.log.debug('The frontend sent /api/plugins');
3003
2473
  const response = await this.getBaseRegisteredPlugins();
3004
- // this.log.debug('Response:', debugStringify(response));
3005
2474
  res.json(response);
3006
2475
  });
3007
- // Endpoint to provide devices
3008
2476
  this.expressApp.get('/api/devices', (req, res) => {
3009
2477
  this.log.debug('The frontend sent /api/devices');
3010
2478
  const devices = [];
@@ -3037,10 +2505,8 @@ export class Matterbridge extends EventEmitter {
3037
2505
  cluster: cluster,
3038
2506
  });
3039
2507
  });
3040
- // this.log.debug('Response:', debugStringify(data));
3041
2508
  res.json(devices);
3042
2509
  });
3043
- // Endpoint to provide the cluster servers of the devices
3044
2510
  this.expressApp.get('/api/devices_clusters/:selectedPluginName/:selectedDeviceEndpoint', (req, res) => {
3045
2511
  const selectedPluginName = req.params.selectedPluginName;
3046
2512
  const selectedDeviceEndpoint = parseInt(req.params.selectedDeviceEndpoint, 10);
@@ -3060,7 +2526,6 @@ export class Matterbridge extends EventEmitter {
3060
2526
  Object.entries(clusterServer.attributes).forEach(([key, value]) => {
3061
2527
  if (clusterServer.name === 'EveHistory')
3062
2528
  return;
3063
- // this.log.debug(`***--clusterServer: ${clusterServer.name}(${clusterServer.id}) attribute:${key}(${value.id}) ${value.isFixed} ${value.isWritable} ${value.isWritable}`);
3064
2529
  let attributeValue;
3065
2530
  try {
3066
2531
  if (typeof value.getLocal() === 'object')
@@ -3071,7 +2536,6 @@ export class Matterbridge extends EventEmitter {
3071
2536
  catch (error) {
3072
2537
  attributeValue = 'Fabric-Scoped';
3073
2538
  this.log.debug(`GetLocal value ${error} in clusterServer: ${clusterServer.name}(${clusterServer.id}) attribute: ${key}(${value.id})`);
3074
- // console.log(error);
3075
2539
  }
3076
2540
  data.push({
3077
2541
  endpoint: device.number ? device.number.toString() : '...',
@@ -3084,14 +2548,12 @@ export class Matterbridge extends EventEmitter {
3084
2548
  });
3085
2549
  });
3086
2550
  device.getChildEndpoints().forEach((childEndpoint) => {
3087
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
3088
2551
  const name = this.edge ? childEndpoint.endpoint?.id : childEndpoint.uniqueStorageKey;
3089
2552
  const clusterServers = childEndpoint.getAllClusterServers();
3090
2553
  clusterServers.forEach((clusterServer) => {
3091
2554
  Object.entries(clusterServer.attributes).forEach(([key, value]) => {
3092
2555
  if (clusterServer.name === 'EveHistory')
3093
2556
  return;
3094
- // this.log.debug(`***--clusterServer: ${clusterServer.name}(${clusterServer.id}) attribute:${key}(${value.id}) ${value.isFixed} ${value.isWritable} ${value.isWritable}`);
3095
2557
  let attributeValue;
3096
2558
  try {
3097
2559
  if (typeof value.getLocal() === 'object')
@@ -3102,7 +2564,6 @@ export class Matterbridge extends EventEmitter {
3102
2564
  catch (error) {
3103
2565
  attributeValue = 'Unavailable';
3104
2566
  this.log.debug(`GetLocal error ${error} in clusterServer: ${clusterServer.name}(${clusterServer.id}) attribute: ${key}(${value.id})`);
3105
- // console.log(error);
3106
2567
  }
3107
2568
  data.push({
3108
2569
  endpoint: (childEndpoint.number ? childEndpoint.number.toString() : '...') + (name ? ' (' + name + ')' : ''),
@@ -3119,7 +2580,6 @@ export class Matterbridge extends EventEmitter {
3119
2580
  });
3120
2581
  res.json(data);
3121
2582
  });
3122
- // Endpoint to view the log
3123
2583
  this.expressApp.get('/api/view-log', async (req, res) => {
3124
2584
  this.log.debug('The frontend sent /api/log');
3125
2585
  try {
@@ -3132,12 +2592,10 @@ export class Matterbridge extends EventEmitter {
3132
2592
  res.status(500).send('Error reading log file');
3133
2593
  }
3134
2594
  });
3135
- // Endpoint to download the matterbridge log
3136
2595
  this.expressApp.get('/api/download-mblog', async (req, res) => {
3137
2596
  this.log.debug('The frontend sent /api/download-mblog');
3138
2597
  try {
3139
2598
  await fs.access(path.join(this.matterbridgeDirectory, this.matterbrideLoggerFile), fs.constants.F_OK);
3140
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
3141
2599
  }
3142
2600
  catch (error) {
3143
2601
  fs.appendFile(path.join(this.matterbridgeDirectory, this.matterbrideLoggerFile), 'Enable the log on file in the settings to enable the file logger');
@@ -3149,12 +2607,10 @@ export class Matterbridge extends EventEmitter {
3149
2607
  }
3150
2608
  });
3151
2609
  });
3152
- // Endpoint to download the matter log
3153
2610
  this.expressApp.get('/api/download-mjlog', async (req, res) => {
3154
2611
  this.log.debug('The frontend sent /api/download-mjlog');
3155
2612
  try {
3156
2613
  await fs.access(path.join(this.matterbridgeDirectory, this.matterLoggerFile), fs.constants.F_OK);
3157
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
3158
2614
  }
3159
2615
  catch (error) {
3160
2616
  fs.appendFile(path.join(this.matterbridgeDirectory, this.matterLoggerFile), 'Enable the log on file in the settings to enable the file logger');
@@ -3166,7 +2622,6 @@ export class Matterbridge extends EventEmitter {
3166
2622
  }
3167
2623
  });
3168
2624
  });
3169
- // Endpoint to download the matter storage file
3170
2625
  this.expressApp.get('/api/download-mjstorage', (req, res) => {
3171
2626
  this.log.debug('The frontend sent /api/download-mjstorage');
3172
2627
  res.download(path.join(this.matterbridgeDirectory, this.matterStorageName), 'matterbridge.json', (error) => {
@@ -3176,7 +2631,6 @@ export class Matterbridge extends EventEmitter {
3176
2631
  }
3177
2632
  });
3178
2633
  });
3179
- // Endpoint to download the matterbridge storage directory
3180
2634
  this.expressApp.get('/api/download-mbstorage', async (req, res) => {
3181
2635
  this.log.debug('The frontend sent /api/download-mbstorage');
3182
2636
  await createZip(path.join(os.tmpdir(), `matterbridge.${this.nodeStorageName}.zip`), path.join(this.matterbridgeDirectory, this.nodeStorageName));
@@ -3187,7 +2641,6 @@ export class Matterbridge extends EventEmitter {
3187
2641
  }
3188
2642
  });
3189
2643
  });
3190
- // Endpoint to download the matterbridge plugin directory
3191
2644
  this.expressApp.get('/api/download-pluginstorage', async (req, res) => {
3192
2645
  this.log.debug('The frontend sent /api/download-pluginstorage');
3193
2646
  await createZip(path.join(os.tmpdir(), `matterbridge.pluginstorage.zip`), this.matterbridgePluginDirectory);
@@ -3198,11 +2651,9 @@ export class Matterbridge extends EventEmitter {
3198
2651
  }
3199
2652
  });
3200
2653
  });
3201
- // Endpoint to download the matterbridge plugin config files
3202
2654
  this.expressApp.get('/api/download-pluginconfig', async (req, res) => {
3203
2655
  this.log.debug('The frontend sent /api/download-pluginconfig');
3204
2656
  await createZip(path.join(os.tmpdir(), `matterbridge.pluginconfig.zip`), path.relative(process.cwd(), path.join(this.matterbridgeDirectory, '*.config.json')));
3205
- // 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')));
3206
2657
  res.download(path.join(os.tmpdir(), `matterbridge.pluginconfig.zip`), `matterbridge.pluginconfig.zip`, (error) => {
3207
2658
  if (error) {
3208
2659
  this.log.error(`Error downloading file matterbridge.pluginstorage.zip: ${error instanceof Error ? error.message : error}`);
@@ -3210,7 +2661,6 @@ export class Matterbridge extends EventEmitter {
3210
2661
  }
3211
2662
  });
3212
2663
  });
3213
- // Endpoint to download the matterbridge plugin config files
3214
2664
  this.expressApp.get('/api/download-backup', async (req, res) => {
3215
2665
  this.log.debug('The frontend sent /api/download-backup');
3216
2666
  res.download(path.join(os.tmpdir(), `matterbridge.backup.zip`), `matterbridge.backup.zip`, (error) => {
@@ -3220,7 +2670,6 @@ export class Matterbridge extends EventEmitter {
3220
2670
  }
3221
2671
  });
3222
2672
  });
3223
- // Endpoint to receive commands
3224
2673
  this.expressApp.post('/api/command/:command/:param', express.json(), async (req, res) => {
3225
2674
  const command = req.params.command;
3226
2675
  let param = req.params.param;
@@ -3230,15 +2679,13 @@ export class Matterbridge extends EventEmitter {
3230
2679
  return;
3231
2680
  }
3232
2681
  this.log.debug(`Received frontend command: ${command}:${param}`);
3233
- // Handle the command setpassword from Settings
3234
2682
  if (command === 'setpassword') {
3235
- const password = param.slice(1, -1); // Remove the first and last characters
2683
+ const password = param.slice(1, -1);
3236
2684
  this.log.debug('setpassword', param, password);
3237
2685
  await this.nodeContext?.set('password', password);
3238
2686
  res.json({ message: 'Command received' });
3239
2687
  return;
3240
2688
  }
3241
- // Handle the command setbridgemode from Settings
3242
2689
  if (command === 'setbridgemode') {
3243
2690
  this.log.debug(`setbridgemode: ${param}`);
3244
2691
  this.wssSendRestartRequired();
@@ -3246,7 +2693,6 @@ export class Matterbridge extends EventEmitter {
3246
2693
  res.json({ message: 'Command received' });
3247
2694
  return;
3248
2695
  }
3249
- // Handle the command backup from Settings
3250
2696
  if (command === 'backup') {
3251
2697
  this.log.notice(`Prepairing the backup...`);
3252
2698
  await createZip(path.join(os.tmpdir(), `matterbridge.backup.zip`), path.join(this.matterbridgeDirectory), path.join(this.matterbridgePluginDirectory));
@@ -3254,26 +2700,25 @@ export class Matterbridge extends EventEmitter {
3254
2700
  res.json({ message: 'Command received' });
3255
2701
  return;
3256
2702
  }
3257
- // Handle the command setmbloglevel from Settings
3258
2703
  if (command === 'setmbloglevel') {
3259
2704
  this.log.debug('Matterbridge log level:', param);
3260
2705
  if (param === 'Debug') {
3261
- this.log.logLevel = "debug" /* LogLevel.DEBUG */;
2706
+ this.log.logLevel = "debug";
3262
2707
  }
3263
2708
  else if (param === 'Info') {
3264
- this.log.logLevel = "info" /* LogLevel.INFO */;
2709
+ this.log.logLevel = "info";
3265
2710
  }
3266
2711
  else if (param === 'Notice') {
3267
- this.log.logLevel = "notice" /* LogLevel.NOTICE */;
2712
+ this.log.logLevel = "notice";
3268
2713
  }
3269
2714
  else if (param === 'Warn') {
3270
- this.log.logLevel = "warn" /* LogLevel.WARN */;
2715
+ this.log.logLevel = "warn";
3271
2716
  }
3272
2717
  else if (param === 'Error') {
3273
- this.log.logLevel = "error" /* LogLevel.ERROR */;
2718
+ this.log.logLevel = "error";
3274
2719
  }
3275
2720
  else if (param === 'Fatal') {
3276
- this.log.logLevel = "fatal" /* LogLevel.FATAL */;
2721
+ this.log.logLevel = "fatal";
3277
2722
  }
3278
2723
  await this.nodeContext?.set('matterbridgeLogLevel', this.log.logLevel);
3279
2724
  MatterbridgeDevice.logLevel = this.log.logLevel;
@@ -3281,13 +2726,12 @@ export class Matterbridge extends EventEmitter {
3281
2726
  for (const plugin of this.plugins) {
3282
2727
  if (!plugin.platform || !plugin.platform.config)
3283
2728
  continue;
3284
- plugin.platform.log.logLevel = plugin.platform.config.debug ? "debug" /* LogLevel.DEBUG */ : this.log.logLevel;
3285
- await plugin.platform.onChangeLoggerLevel(plugin.platform.config.debug ? "debug" /* LogLevel.DEBUG */ : this.log.logLevel);
2729
+ plugin.platform.log.logLevel = plugin.platform.config.debug ? "debug" : this.log.logLevel;
2730
+ await plugin.platform.onChangeLoggerLevel(plugin.platform.config.debug ? "debug" : this.log.logLevel);
3286
2731
  }
3287
2732
  res.json({ message: 'Command received' });
3288
2733
  return;
3289
2734
  }
3290
- // Handle the command setmbloglevel from Settings
3291
2735
  if (command === 'setmjloglevel') {
3292
2736
  this.log.debug('Matter.js log level:', param);
3293
2737
  if (param === 'Debug') {
@@ -3312,34 +2756,30 @@ export class Matterbridge extends EventEmitter {
3312
2756
  res.json({ message: 'Command received' });
3313
2757
  return;
3314
2758
  }
3315
- // Handle the command setmdnsinterface from Settings
3316
2759
  if (command === 'setmdnsinterface') {
3317
- param = param.slice(1, -1); // Remove the first and last characters *mdns*
2760
+ param = param.slice(1, -1);
3318
2761
  this.matterbridgeInformation.mattermdnsinterface = param;
3319
2762
  this.log.debug('Matter.js mdns interface:', param === '' ? 'All interfaces' : param);
3320
2763
  await this.nodeContext?.set('mattermdnsinterface', param);
3321
2764
  res.json({ message: 'Command received' });
3322
2765
  return;
3323
2766
  }
3324
- // Handle the command setipv4address from Settings
3325
2767
  if (command === 'setipv4address') {
3326
- param = param.slice(1, -1); // Remove the first and last characters *ip*
2768
+ param = param.slice(1, -1);
3327
2769
  this.matterbridgeInformation.matteripv4address = param;
3328
2770
  this.log.debug('Matter.js ipv4 address:', param === '' ? 'All ipv4 addresses' : param);
3329
2771
  await this.nodeContext?.set('matteripv4address', param);
3330
2772
  res.json({ message: 'Command received' });
3331
2773
  return;
3332
2774
  }
3333
- // Handle the command setipv6address from Settings
3334
2775
  if (command === 'setipv6address') {
3335
- param = param.slice(1, -1); // Remove the first and last characters *ip*
2776
+ param = param.slice(1, -1);
3336
2777
  this.matterbridgeInformation.matteripv6address = param;
3337
2778
  this.log.debug('Matter.js ipv6 address:', param === '' ? 'All ipv6 addresses' : param);
3338
2779
  await this.nodeContext?.set('matteripv6address', param);
3339
2780
  res.json({ message: 'Command received' });
3340
2781
  return;
3341
2782
  }
3342
- // Handle the command setmatterport from Settings
3343
2783
  if (command === 'setmatterport') {
3344
2784
  const port = Math.min(Math.max(parseInt(param), 5540), 5560);
3345
2785
  this.matterbridgeInformation.matterPort = port;
@@ -3348,7 +2788,6 @@ export class Matterbridge extends EventEmitter {
3348
2788
  res.json({ message: 'Command received' });
3349
2789
  return;
3350
2790
  }
3351
- // Handle the command setmatterdiscriminator from Settings
3352
2791
  if (command === 'setmatterdiscriminator') {
3353
2792
  const discriminator = Math.min(Math.max(parseInt(param), 1000), 4095);
3354
2793
  this.matterbridgeInformation.matterDiscriminator = discriminator;
@@ -3357,7 +2796,6 @@ export class Matterbridge extends EventEmitter {
3357
2796
  res.json({ message: 'Command received' });
3358
2797
  return;
3359
2798
  }
3360
- // Handle the command setmatterpasscode from Settings
3361
2799
  if (command === 'setmatterpasscode') {
3362
2800
  const passcode = Math.min(Math.max(parseInt(param), 10000000), 90000000);
3363
2801
  this.matterbridgeInformation.matterPasscode = passcode;
@@ -3366,20 +2804,17 @@ export class Matterbridge extends EventEmitter {
3366
2804
  res.json({ message: 'Command received' });
3367
2805
  return;
3368
2806
  }
3369
- // Handle the command setmbloglevel from Settings
3370
2807
  if (command === 'setmblogfile') {
3371
2808
  this.log.debug('Matterbridge file log:', param);
3372
2809
  this.matterbridgeInformation.fileLogger = param === 'true';
3373
2810
  await this.nodeContext?.set('matterbridgeFileLog', param === 'true');
3374
- // Create the file logger for matterbridge
3375
2811
  if (param === 'true')
3376
- AnsiLogger.setGlobalLogfile(path.join(this.matterbridgeDirectory, this.matterbrideLoggerFile), "debug" /* LogLevel.DEBUG */, true);
2812
+ AnsiLogger.setGlobalLogfile(path.join(this.matterbridgeDirectory, this.matterbrideLoggerFile), "debug", true);
3377
2813
  else
3378
2814
  AnsiLogger.setGlobalLogfile(undefined);
3379
2815
  res.json({ message: 'Command received' });
3380
2816
  return;
3381
2817
  }
3382
- // Handle the command setmbloglevel from Settings
3383
2818
  if (command === 'setmjlogfile') {
3384
2819
  this.log.debug('Matter file log:', param);
3385
2820
  this.matterbridgeInformation.matterFileLogger = param === 'true';
@@ -3406,43 +2841,36 @@ export class Matterbridge extends EventEmitter {
3406
2841
  res.json({ message: 'Command received' });
3407
2842
  return;
3408
2843
  }
3409
- // Handle the command unregister from Settings
3410
2844
  if (command === 'unregister') {
3411
2845
  await this.unregisterAndShutdownProcess();
3412
2846
  res.json({ message: 'Command received' });
3413
2847
  return;
3414
2848
  }
3415
- // Handle the command reset from Settings
3416
2849
  if (command === 'reset') {
3417
2850
  await this.shutdownProcessAndReset();
3418
2851
  res.json({ message: 'Command received' });
3419
2852
  return;
3420
2853
  }
3421
- // Handle the command factoryreset from Settings
3422
2854
  if (command === 'factoryreset') {
3423
2855
  await this.shutdownProcessAndFactoryReset();
3424
2856
  res.json({ message: 'Command received' });
3425
2857
  return;
3426
2858
  }
3427
- // Handle the command shutdown from Header
3428
2859
  if (command === 'shutdown') {
3429
2860
  await this.shutdownProcess();
3430
2861
  res.json({ message: 'Command received' });
3431
2862
  return;
3432
2863
  }
3433
- // Handle the command restart from Header
3434
2864
  if (command === 'restart') {
3435
2865
  await this.restartProcess();
3436
2866
  res.json({ message: 'Command received' });
3437
2867
  return;
3438
2868
  }
3439
- // Handle the command update from Header
3440
2869
  if (command === 'update') {
3441
2870
  this.log.info('Updating matterbridge...');
3442
2871
  try {
3443
2872
  await this.spawnCommand('npm', ['install', '-g', 'matterbridge', '--omit=dev', '--verbose']);
3444
2873
  this.log.info('Matterbridge has been updated. Full restart required.');
3445
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
3446
2874
  }
3447
2875
  catch (error) {
3448
2876
  this.log.error('Error updating matterbridge');
@@ -3452,11 +2880,9 @@ export class Matterbridge extends EventEmitter {
3452
2880
  res.json({ message: 'Command received' });
3453
2881
  return;
3454
2882
  }
3455
- // Handle the command saveconfig from Home
3456
2883
  if (command === 'saveconfig') {
3457
2884
  param = param.replace(/\*/g, '\\');
3458
2885
  this.log.info(`Saving config for plugin ${plg}${param}${nf}...`);
3459
- // console.log('Req.body:', JSON.stringify(req.body, null, 2));
3460
2886
  if (!this.plugins.has(param)) {
3461
2887
  this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
3462
2888
  }
@@ -3470,39 +2896,33 @@ export class Matterbridge extends EventEmitter {
3470
2896
  res.json({ message: 'Command received' });
3471
2897
  return;
3472
2898
  }
3473
- // Handle the command installplugin from Home
3474
2899
  if (command === 'installplugin') {
3475
2900
  param = param.replace(/\*/g, '\\');
3476
2901
  this.log.info(`Installing plugin ${plg}${param}${nf}...`);
3477
2902
  try {
3478
2903
  await this.spawnCommand('npm', ['install', '-g', param, '--omit=dev', '--verbose']);
3479
2904
  this.log.info(`Plugin ${plg}${param}${nf} installed. Full restart required.`);
3480
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
3481
2905
  }
3482
2906
  catch (error) {
3483
2907
  this.log.error(`Error installing plugin ${plg}${param}${er}`);
3484
2908
  }
3485
2909
  this.wssSendRestartRequired();
3486
2910
  param = param.split('@')[0];
3487
- // Also add the plugin to matterbridge so no return!
3488
2911
  if (param === 'matterbridge') {
3489
- // If we used the command installplugin to install a dev or a specific version of matterbridge we don't want to add it to matterbridge
3490
2912
  res.json({ message: 'Command received' });
3491
2913
  return;
3492
2914
  }
3493
2915
  }
3494
- // Handle the command addplugin from Home
3495
2916
  if (command === 'addplugin' || command === 'installplugin') {
3496
2917
  param = param.replace(/\*/g, '\\');
3497
2918
  const plugin = await this.plugins.add(param);
3498
2919
  if (plugin) {
3499
- this.plugins.load(plugin, true, 'The plugin has been added', true); // No await do it in the background
2920
+ this.plugins.load(plugin, true, 'The plugin has been added', true);
3500
2921
  }
3501
2922
  res.json({ message: 'Command received' });
3502
2923
  this.wssSendRefreshRequired();
3503
2924
  return;
3504
2925
  }
3505
- // Handle the command removeplugin from Home
3506
2926
  if (command === 'removeplugin') {
3507
2927
  if (!this.plugins.has(param)) {
3508
2928
  this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
@@ -3516,7 +2936,6 @@ export class Matterbridge extends EventEmitter {
3516
2936
  this.wssSendRefreshRequired();
3517
2937
  return;
3518
2938
  }
3519
- // Handle the command enableplugin from Home
3520
2939
  if (command === 'enableplugin') {
3521
2940
  if (!this.plugins.has(param)) {
3522
2941
  this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
@@ -3534,14 +2953,13 @@ export class Matterbridge extends EventEmitter {
3534
2953
  plugin.registeredDevices = undefined;
3535
2954
  plugin.addedDevices = undefined;
3536
2955
  await this.plugins.enable(param);
3537
- this.plugins.load(plugin, true, 'The plugin has been enabled', true); // No await do it in the background
2956
+ this.plugins.load(plugin, true, 'The plugin has been enabled', true);
3538
2957
  }
3539
2958
  }
3540
2959
  res.json({ message: 'Command received' });
3541
2960
  this.wssSendRefreshRequired();
3542
2961
  return;
3543
2962
  }
3544
- // Handle the command disableplugin from Home
3545
2963
  if (command === 'disableplugin') {
3546
2964
  if (!this.plugins.has(param)) {
3547
2965
  this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
@@ -3558,7 +2976,6 @@ export class Matterbridge extends EventEmitter {
3558
2976
  return;
3559
2977
  }
3560
2978
  });
3561
- // Fallback for routing (must be the last route)
3562
2979
  this.expressApp.get('*', (req, res) => {
3563
2980
  this.log.debug('The frontend sent:', req.url);
3564
2981
  this.log.debug('Response send file:', path.join(this.rootDirectory, 'frontend/build/index.html'));
@@ -3566,11 +2983,6 @@ export class Matterbridge extends EventEmitter {
3566
2983
  });
3567
2984
  this.log.debug(`Frontend initialized on port ${YELLOW}${port}${db} static ${UNDERLINE}${path.join(this.rootDirectory, 'frontend/build')}${UNDERLINEOFF}${rs}`);
3568
2985
  }
3569
- /**
3570
- * Retrieves the cluster text description from a given device.
3571
- * @param {MatterbridgeDevice} device - The MatterbridgeDevice object.
3572
- * @returns {string} The attributes description of the cluster servers in the device.
3573
- */
3574
2986
  getClusterTextFromDevice(device) {
3575
2987
  const stringifyUserLabel = (endpoint) => {
3576
2988
  const labelList = endpoint.getClusterServer(UserLabelCluster)?.attributes.labelList.getLocal();
@@ -3593,11 +3005,9 @@ export class Matterbridge extends EventEmitter {
3593
3005
  return '';
3594
3006
  };
3595
3007
  let attributes = '';
3596
- // this.log.debug(`***getClusterTextFromDevice: ${device.deviceName} (${device.name})`);
3597
3008
  const clusterServers = device.getAllClusterServers();
3598
3009
  clusterServers.forEach((clusterServer) => {
3599
3010
  try {
3600
- // this.log.debug(`**--clusterServer: ${clusterServer.id} (${clusterServer.name})`);
3601
3011
  if (clusterServer.name === 'OnOff')
3602
3012
  attributes += `OnOff: ${clusterServer.attributes.onOff.getLocal()} `;
3603
3013
  if (clusterServer.name === 'Switch')
@@ -3648,30 +3058,18 @@ export class Matterbridge extends EventEmitter {
3648
3058
  attributes += `${stringifyFixedLabel(device)} `;
3649
3059
  if (clusterServer.name === 'UserLabel')
3650
3060
  attributes += `${stringifyUserLabel(device)} `;
3651
- // this.log.debug(`*--clusterServer: ${clusterServer.id} (${clusterServer.name})`);
3652
3061
  }
3653
3062
  catch (error) {
3654
3063
  this.log.error(`getClusterTextFromDevice with ${clusterServer.name} error: ${error}`);
3655
3064
  }
3656
3065
  });
3657
- // this.log.debug(`*getClusterTextFromDevice: ${device.deviceName} (${device.name})`);
3658
3066
  return attributes;
3659
3067
  }
3660
- /**
3661
- * Initializes the Matterbridge instance as extension for zigbee2mqtt.
3662
- * @deprecated This method is deprecated and will be removed in a future version.
3663
- *
3664
- * @returns A Promise that resolves when the initialization is complete.
3665
- */
3666
3068
  async startExtension(dataPath, extensionVersion, port = 5540) {
3667
- // Set the bridge mode
3668
3069
  this.bridgeMode = 'bridge';
3669
- // Set the first port to use
3670
3070
  this.port = port;
3671
- // Set Matterbridge logger
3672
- this.log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: "info" /* LogLevel.INFO */ });
3071
+ this.log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4, logLevel: "info" });
3673
3072
  this.log.debug('Matterbridge extension is starting...');
3674
- // Initialize NodeStorage
3675
3073
  this.matterbridgeDirectory = dataPath;
3676
3074
  this.log.debug('Creating node storage manager dir: ' + path.join(this.matterbridgeDirectory, 'node_storage'));
3677
3075
  this.nodeStorage = new NodeStorageManager({ dir: path.join(this.matterbridgeDirectory, 'node_storage'), logging: false });
@@ -3690,13 +3088,10 @@ export class Matterbridge extends EventEmitter {
3690
3088
  };
3691
3089
  this.plugins.set(plugin);
3692
3090
  this.plugins.saveToStorage();
3693
- // Log system info and create .matterbridge directory
3694
3091
  await this.logNodeAndSystemInfo();
3695
3092
  this.matterbridgeDirectory = dataPath;
3696
- // Set matter.js logger level and format
3697
3093
  Logger.defaultLogLevel = MatterLogLevel.INFO;
3698
3094
  Logger.format = MatterLogFormat.ANSI;
3699
- // Start the storage and create matterbridgeContext
3700
3095
  await this.startMatterStorage('json', path.join(this.matterbridgeDirectory, this.matterStorageName));
3701
3096
  if (!this.storageManager)
3702
3097
  return false;
@@ -3706,7 +3101,7 @@ export class Matterbridge extends EventEmitter {
3706
3101
  await this.matterbridgeContext.set('softwareVersion', 1);
3707
3102
  await this.matterbridgeContext.set('softwareVersionString', this.matterbridgeVersion);
3708
3103
  await this.matterbridgeContext.set('hardwareVersion', 1);
3709
- await this.matterbridgeContext.set('hardwareVersionString', extensionVersion); // Update with the extension version
3104
+ await this.matterbridgeContext.set('hardwareVersionString', extensionVersion);
3710
3105
  this.matterServer = this.createMatterServer(this.storageManager);
3711
3106
  this.log.debug(`Creating commissioning server for ${plg}Matterbridge${db}`);
3712
3107
  this.commissioningServer = await this.createCommisioningServer(this.matterbridgeContext, 'Matterbridge');
@@ -3719,7 +3114,6 @@ export class Matterbridge extends EventEmitter {
3719
3114
  await this.startMatterServer();
3720
3115
  this.log.info('Matter server started');
3721
3116
  await this.showCommissioningQRCode(this.commissioningServer, this.matterbridgeContext, this.nodeContext, 'Matterbridge');
3722
- // Set reachability to true and trigger event after 60 seconds
3723
3117
  setTimeout(() => {
3724
3118
  this.log.info(`Setting reachability to true for ${plg}Matterbridge${db}`);
3725
3119
  if (this.commissioningServer)
@@ -3729,31 +3123,14 @@ export class Matterbridge extends EventEmitter {
3729
3123
  }, 60 * 1000);
3730
3124
  return this.commissioningServer.isCommissioned();
3731
3125
  }
3732
- /**
3733
- * Close the Matterbridge instance as extension for zigbee2mqtt.
3734
- * @deprecated This method is deprecated and will be removed in a future version.
3735
- *
3736
- * @returns A Promise that resolves when the initialization is complete.
3737
- */
3738
3126
  async stopExtension() {
3739
- // Closing matter
3740
3127
  await this.stopMatterServer();
3741
- // Clearing the session manager
3742
- // this.matterbridgeContext?.createContext('SessionManager').clear();
3743
- // Closing storage
3744
3128
  await this.stopMatterStorage();
3745
3129
  this.log.info('Matter server stopped');
3746
3130
  }
3747
- /**
3748
- * Checks if the extension is commissioned.
3749
- * @deprecated This method is deprecated and will be removed in a future version.
3750
- *
3751
- * @returns {boolean} Returns true if the extension is commissioned, false otherwise.
3752
- */
3753
3131
  isExtensionCommissioned() {
3754
3132
  if (!this.commissioningServer)
3755
3133
  return false;
3756
3134
  return this.commissioningServer.isCommissioned();
3757
3135
  }
3758
3136
  }
3759
- //# sourceMappingURL=matterbridge.js.map