matterbridge 1.6.8-dev.2 → 1.6.8-dev.4

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 +7 -6
  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 +165 -660
  10. package/dist/matterbridgeAccessoryPlatform.js +0 -33
  11. package/dist/matterbridgeBehaviors.js +1 -29
  12. package/dist/matterbridgeDevice.js +9 -995
  13. package/dist/matterbridgeDeviceTypes.js +11 -82
  14. package/dist/matterbridgeDynamicPlatform.js +0 -33
  15. package/dist/matterbridgeEdge.js +2 -531
  16. package/dist/matterbridgeEndpoint.js +11 -1120
  17. package/dist/matterbridgePlatform.js +3 -91
  18. package/dist/matterbridgeTypes.js +0 -24
  19. package/dist/matterbridgeWebsocket.js +0 -45
  20. package/dist/pluginManager.js +3 -238
  21. package/dist/storage/export.js +0 -1
  22. package/dist/utils/colorUtils.js +2 -205
  23. package/dist/utils/export.js +0 -1
  24. package/dist/utils/utils.js +7 -252
  25. package/npm-shrinkwrap.json +6 -6
  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 -466
  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 -114
  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
- import { DeviceTypeId, Logger, LogLevel as MatterLogLevel, LogFormat as MatterLogFormat, VendorId, StorageManager, EndpointServer } from '@matter/main';
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,35 +990,26 @@ export class Matterbridge extends EventEmitter {
1210
990
  });
1211
991
  this.webSocketServer = undefined;
1212
992
  }
1213
- // Closing matter
1214
993
  await this.stopMatterServer();
1215
- // Closing matter storage
1216
994
  await this.stopMatterStorage();
1217
- // Remove the matterfilelogger
1218
995
  try {
1219
996
  Logger.removeLogger('matterfilelogger');
1220
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1221
997
  }
1222
998
  catch (error) {
1223
- // this.log.debug(`Error removing the matterfilelogger for file ${CYAN}${path.join(this.matterbridgeDirectory, this.matterLoggerFile)}${er}: ${error instanceof Error ? error.message : error}`);
1224
999
  }
1225
- // Serialize registeredDevices
1226
1000
  if (this.nodeStorage && this.nodeContext) {
1227
1001
  this.log.info('Saving registered devices...');
1228
1002
  const serializedRegisteredDevices = [];
1229
1003
  this.devices.forEach(async (device) => {
1230
1004
  const serializedMatterbridgeDevice = device.serialize();
1231
- // this.log.info(`- ${serializedMatterbridgeDevice.deviceName}${rs}\n`, serializedMatterbridgeDevice);
1232
1005
  if (serializedMatterbridgeDevice)
1233
1006
  serializedRegisteredDevices.push(serializedMatterbridgeDevice);
1234
1007
  });
1235
1008
  await this.nodeContext.set('devices', serializedRegisteredDevices);
1236
1009
  this.log.info(`Saved registered devices (${serializedRegisteredDevices?.length})`);
1237
- // Clear nodeContext and nodeStorage (they just need 1000ms to write the data to disk)
1238
1010
  this.log.debug(`Closing node storage context for ${plg}Matterbridge${db}...`);
1239
1011
  await this.nodeContext.close();
1240
1012
  this.nodeContext = undefined;
1241
- // Clear nodeContext for each plugin (they just need 1000ms to write the data to disk)
1242
1013
  for (const plugin of this.plugins) {
1243
1014
  if (plugin.nodeContext) {
1244
1015
  this.log.debug(`Closing node storage context for plugin ${plg}${plugin.name}${db}...`);
@@ -1269,16 +1040,13 @@ export class Matterbridge extends EventEmitter {
1269
1040
  }
1270
1041
  else {
1271
1042
  if (message === 'shutting down with reset...') {
1272
- // Delete matter storage file
1273
1043
  this.log.info('Resetting Matterbridge commissioning information...');
1274
1044
  await fs.unlink(path.join(this.matterbridgeDirectory, this.matterStorageName));
1275
1045
  this.log.info('Reset done! Remove all paired devices from the controllers.');
1276
1046
  }
1277
1047
  if (message === 'shutting down with factory reset...') {
1278
- // Delete matter storage file
1279
1048
  this.log.info('Resetting Matterbridge commissioning information...');
1280
1049
  await fs.unlink(path.join(this.matterbridgeDirectory, this.matterStorageName));
1281
- // Delete node storage directory with its subdirectories
1282
1050
  this.log.info('Resetting Matterbridge storage...');
1283
1051
  await fs.rm(path.join(this.matterbridgeDirectory, this.nodeStorageName), { recursive: true });
1284
1052
  this.log.info('Factory reset done! Remove all paired devices from the controllers.');
@@ -1291,33 +1059,19 @@ export class Matterbridge extends EventEmitter {
1291
1059
  this.initialized = false;
1292
1060
  }
1293
1061
  }
1294
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1295
1062
  async addBridgedEndpoint(pluginName, device) {
1296
- // Nothing to do here
1297
1063
  }
1298
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1299
1064
  async removeBridgedEndpoint(pluginName, device) {
1300
- // Nothing to do here
1301
1065
  }
1302
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1303
1066
  async removeAllBridgedEndpoints(pluginName) {
1304
- // Nothing to do here
1305
1067
  }
1306
- /**
1307
- * Adds a bridged device to the Matterbridge.
1308
- * @param pluginName - The name of the plugin.
1309
- * @param device - The bridged device to add.
1310
- * @returns {Promise<void>} - A promise that resolves when the device is added.
1311
- */
1312
1068
  async addBridgedDevice(pluginName, device) {
1313
1069
  this.log.debug(`Adding bridged device ${dev}${device.deviceName}${db} (${zb}${device.name}${db}) for plugin ${plg}${pluginName}${db}`);
1314
- // Check if the plugin is registered
1315
1070
  const plugin = this.plugins.get(pluginName);
1316
1071
  if (!plugin) {
1317
1072
  this.log.error(`Error adding bridged device ${dev}${device.deviceName}${er} (${zb}${device.name}${er}) plugin ${plg}${pluginName}${er} not found`);
1318
1073
  return;
1319
1074
  }
1320
- // Register and add the device to matterbridge aggregator in bridge mode
1321
1075
  if (this.bridgeMode === 'bridge') {
1322
1076
  if (!this.matterAggregator) {
1323
1077
  this.log.error(`Adding bridged device ${dev}${device.deviceName}${er} (${zb}${device.name}${er}) for plugin ${plg}${pluginName}${er} error: matterAggregator not found`);
@@ -1325,11 +1079,8 @@ export class Matterbridge extends EventEmitter {
1325
1079
  }
1326
1080
  this.matterAggregator.addBridgedDevice(device);
1327
1081
  }
1328
- // The first time create the commissioning server and the aggregator for DynamicPlatform
1329
- // Register and add the device in childbridge mode
1330
1082
  if (this.bridgeMode === 'childbridge') {
1331
1083
  if (plugin.type === 'AccessoryPlatform') {
1332
- // Check if the plugin is locked with the commissioning server
1333
1084
  if (!plugin.locked) {
1334
1085
  plugin.locked = true;
1335
1086
  plugin.storageContext = await this.importCommissioningServerContext(plugin.name, device);
@@ -1343,7 +1094,6 @@ export class Matterbridge extends EventEmitter {
1343
1094
  }
1344
1095
  }
1345
1096
  if (plugin.type === 'DynamicPlatform') {
1346
- // Check if the plugin is locked with the commissioning server and the aggregator
1347
1097
  if (!plugin.locked) {
1348
1098
  plugin.locked = true;
1349
1099
  this.log.debug(`Creating commissioning server context for ${plg}${plugin.name}${db}`);
@@ -1364,25 +1114,16 @@ export class Matterbridge extends EventEmitter {
1364
1114
  plugin.registeredDevices++;
1365
1115
  if (plugin.addedDevices !== undefined)
1366
1116
  plugin.addedDevices++;
1367
- // Add the device to the DeviceManager
1368
1117
  this.devices.set(device);
1369
1118
  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}`);
1370
1119
  }
1371
- /**
1372
- * Removes a bridged device from the Matterbridge.
1373
- * @param pluginName - The name of the plugin.
1374
- * @param device - The device to be removed.
1375
- * @returns A Promise that resolves when the device is successfully removed.
1376
- */
1377
1120
  async removeBridgedDevice(pluginName, device) {
1378
1121
  this.log.debug(`Removing bridged device ${dev}${device.deviceName}${db} (${zb}${device.name}${db}) for plugin ${plg}${pluginName}${db}`);
1379
- // Check if the plugin is registered
1380
1122
  const plugin = this.plugins.get(pluginName);
1381
1123
  if (!plugin) {
1382
1124
  this.log.error(`Error removing bridged device ${dev}${device.deviceName}${er} (${zb}${device.name}${er}) for plugin ${plg}${pluginName}${er}: plugin not found`);
1383
1125
  return;
1384
1126
  }
1385
- // Remove the device from matterbridge aggregator in bridge mode
1386
1127
  if (this.bridgeMode === 'bridge') {
1387
1128
  if (!this.matterAggregator) {
1388
1129
  this.log.error(`Error removing bridged device ${dev}${device.deviceName}${er} (${zb}${device.name}${er}) for plugin ${plg}${pluginName}${er}: matterAggregator not found`);
@@ -1392,8 +1133,6 @@ export class Matterbridge extends EventEmitter {
1392
1133
  device.setBridgedDeviceReachability(false);
1393
1134
  device.getClusterServerById(BridgedDeviceBasicInformation.Cluster.id)?.triggerReachableChangedEvent({ reachableNewValue: false });
1394
1135
  }
1395
- // device.getClusterServerById(BridgedDeviceBasicInformation.Cluster.id)?.triggerShutDownEvent({});
1396
- // device.getClusterServerById(BridgedDeviceBasicInformation.Cluster.id)?.triggerLeaveEvent({});
1397
1136
  this.matterAggregator?.removeBridgedDevice(device);
1398
1137
  this.log.info(`Removed bridged device(${plugin.registeredDevices}/${plugin.addedDevices}) ${dev}${device.deviceName}${nf} (${zb}${device.name}${nf}) for plugin ${plg}${pluginName}${nf}`);
1399
1138
  if (plugin.registeredDevices !== undefined)
@@ -1401,7 +1140,6 @@ export class Matterbridge extends EventEmitter {
1401
1140
  if (plugin.addedDevices !== undefined)
1402
1141
  plugin.addedDevices--;
1403
1142
  }
1404
- // Remove the device in childbridge mode
1405
1143
  if (this.bridgeMode === 'childbridge') {
1406
1144
  if (plugin.type === 'AccessoryPlatform') {
1407
1145
  if (!plugin.commissioningServer) {
@@ -1425,22 +1163,14 @@ export class Matterbridge extends EventEmitter {
1425
1163
  plugin.registeredDevices--;
1426
1164
  if (plugin.addedDevices !== undefined)
1427
1165
  plugin.addedDevices--;
1428
- // Remove the commissioning server
1429
1166
  if (plugin.registeredDevices === 0 && plugin.addedDevices === 0 && plugin.commissioningServer) {
1430
1167
  this.matterServer?.removeCommissioningServer(plugin.commissioningServer);
1431
1168
  plugin.commissioningServer = undefined;
1432
1169
  this.log.info(`Removed commissioning server for plugin ${plg}${pluginName}${nf}`);
1433
1170
  }
1434
1171
  }
1435
- // Remove the device from the DeviceManager
1436
1172
  this.devices.remove(device);
1437
1173
  }
1438
- /**
1439
- * Removes all bridged devices associated with a specific plugin.
1440
- *
1441
- * @param pluginName - The name of the plugin.
1442
- * @returns A promise that resolves when all devices have been removed.
1443
- */
1444
1174
  async removeAllBridgedDevices(pluginName) {
1445
1175
  this.log.debug(`Removing all bridged devices for plugin ${plg}${pluginName}${db}`);
1446
1176
  this.devices.forEach(async (device) => {
@@ -1449,13 +1179,7 @@ export class Matterbridge extends EventEmitter {
1449
1179
  }
1450
1180
  });
1451
1181
  }
1452
- /**
1453
- * Starts the Matterbridge in bridge mode.
1454
- * @private
1455
- * @returns {Promise<void>} A promise that resolves when the Matterbridge is started.
1456
- */
1457
1182
  async startBridge() {
1458
- // Plugins are configured by a timer when matter server is started and plugin.configured is set to true
1459
1183
  if (!this.storageManager)
1460
1184
  throw new Error('No storage manager initialized');
1461
1185
  if (!this.matterbridgeContext)
@@ -1474,7 +1198,6 @@ export class Matterbridge extends EventEmitter {
1474
1198
  let failCount = 0;
1475
1199
  this.startMatterInterval = setInterval(async () => {
1476
1200
  for (const plugin of this.plugins) {
1477
- // new code to not start the bridge if one plugin is in error cause the controllers will delete the devices loosing all the configuration
1478
1201
  if (!plugin.enabled)
1479
1202
  continue;
1480
1203
  if (plugin.error) {
@@ -1499,18 +1222,15 @@ export class Matterbridge extends EventEmitter {
1499
1222
  clearInterval(this.startMatterInterval);
1500
1223
  this.startMatterInterval = undefined;
1501
1224
  this.log.debug('Cleared startMatterInterval interval for Matterbridge');
1502
- // Start the Matter server
1503
1225
  await this.startMatterServer();
1504
1226
  this.log.notice('Matter server started');
1505
- // Show the QR code for commissioning or log the already commissioned message
1506
1227
  await this.showCommissioningQRCode(this.commissioningServer, this.matterbridgeContext, this.nodeContext, 'Matterbridge');
1507
- // Configure the plugins
1508
1228
  this.configureTimeout = setTimeout(async () => {
1509
1229
  for (const plugin of this.plugins) {
1510
1230
  if (!plugin.enabled || !plugin.loaded || !plugin.started || plugin.error)
1511
1231
  continue;
1512
1232
  try {
1513
- await this.plugins.configure(plugin); // TODO No await do it in parallel
1233
+ await this.plugins.configure(plugin);
1514
1234
  }
1515
1235
  catch (error) {
1516
1236
  plugin.error = true;
@@ -1519,7 +1239,6 @@ export class Matterbridge extends EventEmitter {
1519
1239
  }
1520
1240
  this.wssSendRefreshRequired();
1521
1241
  }, 30 * 1000);
1522
- // Setting reachability to true
1523
1242
  this.reachabilityTimeout = setTimeout(() => {
1524
1243
  this.log.info(`Setting reachability to true for ${plg}Matterbridge${db}`);
1525
1244
  if (this.commissioningServer)
@@ -1529,14 +1248,7 @@ export class Matterbridge extends EventEmitter {
1529
1248
  }, 60 * 1000);
1530
1249
  }, 1000);
1531
1250
  }
1532
- /**
1533
- * Starts the Matterbridge in childbridge mode.
1534
- * @private
1535
- * @returns {Promise<void>} A promise that resolves when the Matterbridge is started.
1536
- */
1537
1251
  async startChildbridge() {
1538
- // Matterbridge.addBridgedDevice creates the commissionig servers and add the devices to the the commissioning server or to the aggregator
1539
- // Plugins are configured by a timer when matter server is started and plugin.configured is set to true
1540
1252
  if (!this.storageManager)
1541
1253
  throw new Error('No storage manager initialized');
1542
1254
  this.matterServer = this.createMatterServer(this.storageManager);
@@ -1546,7 +1258,6 @@ export class Matterbridge extends EventEmitter {
1546
1258
  this.startMatterInterval = setInterval(async () => {
1547
1259
  let allStarted = true;
1548
1260
  for (const plugin of this.plugins) {
1549
- // new code to not start the bridge if one plugin is in error cause the controllers will delete the devices loosing all the configuration
1550
1261
  if (!plugin.enabled)
1551
1262
  continue;
1552
1263
  if (plugin.error) {
@@ -1574,16 +1285,14 @@ export class Matterbridge extends EventEmitter {
1574
1285
  clearInterval(this.startMatterInterval);
1575
1286
  this.startMatterInterval = undefined;
1576
1287
  this.log.debug('Cleared startMatterInterval interval in childbridge mode');
1577
- // Start the Matter server
1578
1288
  await this.startMatterServer();
1579
1289
  this.log.notice('Matter server started');
1580
- // Configure the plugins
1581
1290
  this.configureTimeout = setTimeout(async () => {
1582
1291
  for (const plugin of this.plugins) {
1583
1292
  if (!plugin.enabled || !plugin.loaded || !plugin.started || plugin.error)
1584
1293
  continue;
1585
1294
  try {
1586
- await this.plugins.configure(plugin); // TODO No await do it in parallel
1295
+ await this.plugins.configure(plugin);
1587
1296
  }
1588
1297
  catch (error) {
1589
1298
  plugin.error = true;
@@ -1612,7 +1321,6 @@ export class Matterbridge extends EventEmitter {
1612
1321
  continue;
1613
1322
  }
1614
1323
  await this.showCommissioningQRCode(plugin.commissioningServer, plugin.storageContext, plugin.nodeContext, plugin.name);
1615
- // Setting reachability to true
1616
1324
  plugin.reachabilityTimeout = setTimeout(() => {
1617
1325
  this.log.info(`Setting reachability to true for ${plg}${plugin.name}${db}`);
1618
1326
  if (plugin.commissioningServer)
@@ -1625,11 +1333,6 @@ export class Matterbridge extends EventEmitter {
1625
1333
  }
1626
1334
  }, 1000);
1627
1335
  }
1628
- /**
1629
- * Starts the Matterbridge controller.
1630
- * @private
1631
- * @returns {Promise<void>} A promise that resolves when the Matterbridge is started.
1632
- */
1633
1336
  async startController() {
1634
1337
  if (!this.storageManager) {
1635
1338
  this.log.error('No storage manager initialized');
@@ -1692,7 +1395,7 @@ export class Matterbridge extends EventEmitter {
1692
1395
  const nodeId = await this.commissioningController.commissionNode(options);
1693
1396
  this.log.info(`Commissioning successfully done with nodeId: ${nodeId}`);
1694
1397
  this.log.info('ActiveSessionInformation:', this.commissioningController.getActiveSessionInformation());
1695
- } // (hasParameter('pairingcode'))
1398
+ }
1696
1399
  if (hasParameter('unpairall')) {
1697
1400
  this.log.info('***Commissioning controller unpairing all nodes...');
1698
1401
  const nodeIds = this.commissioningController.getCommissionedNodes();
@@ -1703,8 +1406,6 @@ export class Matterbridge extends EventEmitter {
1703
1406
  return;
1704
1407
  }
1705
1408
  if (hasParameter('discover')) {
1706
- // const discover = await this.commissioningController.discoverCommissionableDevices({ productId: 0x8000, deviceType: 0xfff1 });
1707
- // console.log(discover);
1708
1409
  }
1709
1410
  if (!this.commissioningController.isCommissioned()) {
1710
1411
  this.log.info('***Commissioning controller is not commissioned: use matterbridge -controller -pairingcode [pairingcode] to commission a device');
@@ -1745,12 +1446,10 @@ export class Matterbridge extends EventEmitter {
1745
1446
  },
1746
1447
  });
1747
1448
  node.logStructure();
1748
- // Get the interaction client
1749
1449
  this.log.info('Getting the interaction client');
1750
1450
  const interactionClient = await node.getInteractionClient();
1751
1451
  let cluster;
1752
1452
  let attributes;
1753
- // Log BasicInformationCluster
1754
1453
  cluster = BasicInformationCluster;
1755
1454
  attributes = await interactionClient.getMultipleAttributes({
1756
1455
  attributes: [{ clusterId: cluster.id }],
@@ -1760,7 +1459,6 @@ export class Matterbridge extends EventEmitter {
1760
1459
  attributes.forEach((attribute) => {
1761
1460
  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}`);
1762
1461
  });
1763
- // Log PowerSourceCluster
1764
1462
  cluster = PowerSourceCluster;
1765
1463
  attributes = await interactionClient.getMultipleAttributes({
1766
1464
  attributes: [{ clusterId: cluster.id }],
@@ -1770,7 +1468,6 @@ export class Matterbridge extends EventEmitter {
1770
1468
  attributes.forEach((attribute) => {
1771
1469
  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}`);
1772
1470
  });
1773
- // Log ThreadNetworkDiagnostics
1774
1471
  cluster = ThreadNetworkDiagnosticsCluster;
1775
1472
  attributes = await interactionClient.getMultipleAttributes({
1776
1473
  attributes: [{ clusterId: cluster.id }],
@@ -1780,7 +1477,6 @@ export class Matterbridge extends EventEmitter {
1780
1477
  attributes.forEach((attribute) => {
1781
1478
  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}`);
1782
1479
  });
1783
- // Log SwitchCluster
1784
1480
  cluster = SwitchCluster;
1785
1481
  attributes = await interactionClient.getMultipleAttributes({
1786
1482
  attributes: [{ clusterId: cluster.id }],
@@ -1801,15 +1497,6 @@ export class Matterbridge extends EventEmitter {
1801
1497
  this.log.info('Subscribed to all attributes and events');
1802
1498
  }
1803
1499
  }
1804
- /** ***********************************************************************************************************************************/
1805
- /** Matter.js methods */
1806
- /** ***********************************************************************************************************************************/
1807
- /**
1808
- * Starts the matter storage process based on the specified storage type and name.
1809
- * @param {string} storageType - The type of storage to start (e.g., 'disk', 'json').
1810
- * @param {string} storageName - The name of the storage file.
1811
- * @returns {Promise<void>} - A promise that resolves when the storage process is started.
1812
- */
1813
1500
  async startMatterStorage(storageType, storageName) {
1814
1501
  this.log.debug(`Starting matter ${storageType} storage ${CYAN}${storageName}${db}`);
1815
1502
  if (storageType === 'disk') {
@@ -1854,13 +1541,110 @@ export class Matterbridge extends EventEmitter {
1854
1541
  }
1855
1542
  this.log.debug(`Creating commissioning server context for ${plg}Matterbridge${db}`);
1856
1543
  this.matterbridgeContext = await this.createCommissioningServerContext('Matterbridge', 'Matterbridge', aggregator.code, 0xfff1, 'Matterbridge', 0x8000, 'Matterbridge aggregator');
1544
+ await this.matterbridgeContext.set('port', this.port);
1545
+ await this.matterbridgeContext.set('passcode', this.passcode);
1546
+ await this.matterbridgeContext.set('discriminator', this.discriminator);
1547
+ }
1548
+ async convertStorage(context, pluginName) {
1549
+ if (!this.matterbridgeContext)
1550
+ return;
1551
+ const storageService = Environment.default.get(StorageService);
1552
+ Environment.default.vars.set('path.root', path.join(this.matterbridgeDirectory, 'matterstorage' + (this.profile ? '.' + this.profile : '')));
1553
+ const nodeStorage = await storageService.open('Matterbridge');
1554
+ if ((await nodeStorage.createContext('persist').get('upgraded', false)) === true) {
1555
+ this.log.info(`Matter node storage already upgraded to Matterbridge edge for ${plg}Matterbridge${nf}`);
1556
+ return;
1557
+ }
1558
+ else {
1559
+ this.log.info(`Upgrading matter node storage to Matterbridge edge for ${plg}Matterbridge${nf}`);
1560
+ }
1561
+ const fabricManagerContext = this.matterbridgeContext.createContext('FabricManager');
1562
+ const fabrics = (await fabricManagerContext.get('fabrics', []));
1563
+ const nextFabricIndex = await fabricManagerContext.get('nextFabricIndex', 1);
1564
+ const eventHandlerContext = this.matterbridgeContext.createContext('EventHandler');
1565
+ const sessionManagerContext = this.matterbridgeContext.createContext('SessionManager');
1566
+ const endpointStructureContext = this.matterbridgeContext.createContext('EndpointStructure');
1567
+ const generalCommissioningContext = this.matterbridgeContext.createContext('Cluster-0-48');
1568
+ const basicInformationContext = this.matterbridgeContext.createContext('Cluster-0-40');
1569
+ const fabricInfo = {};
1570
+ const fabricInfoArray = [];
1571
+ const nocArray = [];
1572
+ const trcArray = [];
1573
+ const aclArray = [];
1574
+ this.log.debug(`Found ${CYAN}${fabrics.length}${db} fabrics (nextFabricIndex ${CYAN}${nextFabricIndex}${db}) for ${plg}Matterbridge${db}:`);
1575
+ for (const fabric of fabrics) {
1576
+ this.log.debug(`- fabricIndex ${CYAN}${fabric.fabricIndex}${db} fabricId ${CYAN}${fabric.fabricId}${db} nodeId ${CYAN}${fabric.nodeId}${db} rootNodeId ${CYAN}${fabric.rootNodeId}${db} rootVendorId ${CYAN}${fabric.rootVendorId}${db} label ${CYAN}${fabric.label}${db}`);
1577
+ fabricInfo[fabric.fabricIndex] = {
1578
+ fabricIndex: fabric.fabricIndex,
1579
+ fabricId: fabric.fabricId,
1580
+ nodeId: fabric.nodeId,
1581
+ rootNodeId: fabric.rootNodeId,
1582
+ rootVendorId: fabric.rootVendorId,
1583
+ label: fabric.label,
1584
+ };
1585
+ fabricInfoArray.push({
1586
+ fabricIndex: fabric.fabricIndex,
1587
+ fabricId: fabric.fabricId,
1588
+ nodeId: fabric.nodeId,
1589
+ vendorId: fabric.rootVendorId,
1590
+ rootPublicKey: fabric.rootPublicKey,
1591
+ label: fabric.label,
1592
+ });
1593
+ nocArray.push({ noc: fabric.operationalCert, icac: null, fabricIndex: fabric.fabricIndex });
1594
+ trcArray.push('{\"__object__\":\"Uint8Array\",\"__value__\":\"' + Buffer.from(fabric.rootCert).toString('hex') + '\"}');
1595
+ aclArray.push({ fabricIndex: fabric.fabricIndex, privilege: 5, authMode: 2, subjects: ['{\"__object__\":\"BigInt\",\"__value__\":\"' + fabric.rootNodeId.toString().replace('n', '') + '\"}'], targets: null });
1596
+ }
1597
+ await nodeStorage.createContext('fabrics').set('fabrics', fabrics);
1598
+ await nodeStorage.createContext('fabrics').set('nextFabricIndex', nextFabricIndex);
1599
+ await nodeStorage.createContext('sessions').set('resumptionRecords', await sessionManagerContext.get('resumptionRecords', []));
1600
+ await nodeStorage.createContext('events').set('lastEventNumber', await eventHandlerContext.get('lastEventNumber', 1));
1601
+ await nodeStorage.createContext('root').set('__number__', 0);
1602
+ await nodeStorage.createContext('root').set('__nextNumber__', 1);
1603
+ await nodeStorage.createContext('root').createContext('commissioning').set('enabled', true);
1604
+ await nodeStorage.createContext('root').createContext('commissioning').set('commissioned', true);
1605
+ await nodeStorage.createContext('root').createContext('commissioning').set('fabrics', fabricInfo);
1606
+ await nodeStorage.createContext('root').createContext('operationalCredentials').set('commissionedFabrics', fabricInfoArray.length);
1607
+ await nodeStorage.createContext('root').createContext('operationalCredentials').set('fabrics', fabricInfoArray);
1608
+ await nodeStorage.createContext('root').createContext('operationalCredentials').set('nocs', nocArray);
1609
+ await nodeStorage.createContext('root').createContext('operationalCredentials').set('trustedRootCertificates', trcArray);
1610
+ await nodeStorage.createContext('root').createContext('accessControl').set('acl', aclArray);
1611
+ await nodeStorage
1612
+ .createContext('root')
1613
+ .createContext('generalCommissioning')
1614
+ .set('breadcrumb', await generalCommissioningContext.get('breadcrumb', BigInt(0)));
1615
+ await nodeStorage
1616
+ .createContext('root')
1617
+ .createContext('basicInformation')
1618
+ .set('location', await basicInformationContext.get('location', 'XX'));
1619
+ await nodeStorage.createContext('root').createContext('network').set('ble', false);
1620
+ await nodeStorage.createContext('root').createContext('network').set('operationalPort', 5540);
1621
+ await nodeStorage.createContext('root').createContext('productDescription').set('productId', 0x8000);
1622
+ await nodeStorage.createContext('root').createContext('productDescription').set('vendorId', 0xfff1);
1623
+ for (const key of await endpointStructureContext.keys()) {
1624
+ if (key === 'nextEndpointId')
1625
+ continue;
1626
+ const parts = key.split('-');
1627
+ const number = await endpointStructureContext.get(key);
1628
+ if (parts.length === 2) {
1629
+ this.log.debug(`Converting Matterbridge.EndpointStructure:${key}:${number} to root.parts.Matterbridge.__number__:${number}`);
1630
+ await nodeStorage.createContext('root').createContext('parts').createContext('Matterbridge').set('__number__', number);
1631
+ }
1632
+ else if (parts.length === 3 && parts[2].startsWith('custom_')) {
1633
+ this.log.debug(`Converting Matterbridge.EndpointStructure:${key}:${number} to root.parts.Matterbridge.parts.${parts[2].replace('custom_', '')}.__number__:${number}`);
1634
+ await nodeStorage.createContext('root').createContext('parts').createContext('Matterbridge').createContext('parts').createContext(parts[2].replace('custom_', '')).set('__number__', number);
1635
+ }
1636
+ else if (parts.length === 3 && parts[2].startsWith('unique_')) {
1637
+ const device = this.devices.get(parts[2].replace('unique_', ''));
1638
+ if (device && device.deviceName && device.maybeNumber) {
1639
+ this.log.debug(`Converting Matterbridge.EndpointStructure:${key}:${number} to root.parts.Matterbridge.parts.${device.deviceName.replace(/[ .]/g, '')}.__number__:${device.maybeNumber}`);
1640
+ await nodeStorage.createContext('root').createContext('parts').createContext('Matterbridge').createContext('parts').createContext(device.deviceName.replace(/[ .]/g, '')).set('__number__', device.maybeNumber);
1641
+ }
1642
+ }
1643
+ }
1644
+ await nodeStorage.createContext('root').createContext('parts').createContext('Matterbridge').set('__number__', 1);
1645
+ await nodeStorage.createContext('persist').set('upgraded', true);
1646
+ await this.matterbridgeContext.set('upgraded', true);
1857
1647
  }
1858
- /**
1859
- * Makes a backup copy of the specified matter JSON storage file.
1860
- *
1861
- * @param storageName - The name of the JSON storage file to be backed up.
1862
- * @param backupName - The name of the backup file to be created.
1863
- */
1864
1648
  async backupMatterStorage(storageName, backupName) {
1865
1649
  try {
1866
1650
  this.log.debug(`Making backup copy of ${storageName}`);
@@ -1881,12 +1665,6 @@ export class Matterbridge extends EventEmitter {
1881
1665
  }
1882
1666
  }
1883
1667
  }
1884
- /**
1885
- * Restore the specified matter JSON storage file.
1886
- *
1887
- * @param backupName - The name of the backup file to restore from.
1888
- * @param storageName - The name of the JSON storage file to restored.
1889
- */
1890
1668
  async restoreMatterStorage(backupName, storageName) {
1891
1669
  try {
1892
1670
  this.log.notice(`Restoring the backup copy of ${storageName}`);
@@ -1907,10 +1685,6 @@ export class Matterbridge extends EventEmitter {
1907
1685
  }
1908
1686
  }
1909
1687
  }
1910
- /**
1911
- * Stops the matter storage.
1912
- * @returns {Promise<void>} A promise that resolves when the storage is stopped.
1913
- */
1914
1688
  async stopMatterStorage() {
1915
1689
  this.log.debug('Stopping storage');
1916
1690
  await this.storageManager?.close();
@@ -1919,14 +1693,8 @@ export class Matterbridge extends EventEmitter {
1919
1693
  this.matterbridgeContext = undefined;
1920
1694
  this.mattercontrollerContext = undefined;
1921
1695
  }
1922
- /**
1923
- * Creates a Matter server using the provided storage manager and the provided mdnsInterface.
1924
- * @param storageManager The storage manager to be used by the Matter server.
1925
- *
1926
- */
1927
1696
  createMatterServer(storageManager) {
1928
1697
  this.log.debug('Creating matter server');
1929
- // Validate mdnsInterface
1930
1698
  if (this.mdnsInterface) {
1931
1699
  const networkInterfaces = os.networkInterfaces();
1932
1700
  const availableInterfaces = Object.keys(networkInterfaces);
@@ -1942,10 +1710,6 @@ export class Matterbridge extends EventEmitter {
1942
1710
  this.log.debug(`Created matter server with mdnsInterface: ${this.mdnsInterface ?? 'all available interfaces'}`);
1943
1711
  return matterServer;
1944
1712
  }
1945
- /**
1946
- * Starts the Matter server.
1947
- * If the Matter server is not initialized, it logs an error and performs cleanup.
1948
- */
1949
1713
  async startMatterServer() {
1950
1714
  if (!this.matterServer) {
1951
1715
  this.log.error('No matter server initialized');
@@ -1955,11 +1719,7 @@ export class Matterbridge extends EventEmitter {
1955
1719
  this.log.debug('Starting matter server...');
1956
1720
  await this.matterServer.start();
1957
1721
  this.log.debug('Started matter server');
1958
- // this.commissioningServer?.getRootEndpoint() && logEndpoint(this.commissioningServer?.getRootEndpoint());
1959
1722
  }
1960
- /**
1961
- * Stops the Matter server, commissioningServer and commissioningController.
1962
- */
1963
1723
  async stopMatterServer() {
1964
1724
  this.log.debug('Stopping matter commissioningServer');
1965
1725
  await this.commissioningServer?.close();
@@ -1973,35 +1733,23 @@ export class Matterbridge extends EventEmitter {
1973
1733
  this.matterAggregator = undefined;
1974
1734
  this.matterServer = undefined;
1975
1735
  }
1976
- /**
1977
- * Creates a Matter Aggregator.
1978
- * @param {StorageContext} context - The storage context.
1979
- * @returns {Aggregator} - The created Matter Aggregator.
1980
- */
1981
1736
  async createMatterAggregator(context, pluginName) {
1982
1737
  this.log.debug(`Creating matter aggregator for ${plg}${pluginName}${db}`);
1983
1738
  const matterAggregator = new Aggregator();
1984
1739
  return matterAggregator;
1985
1740
  }
1986
- /**
1987
- * Creates a matter commissioning server.
1988
- *
1989
- * @param {StorageContext} context - The storage context.
1990
- * @param {string} pluginName - The name of the commissioning server.
1991
- * @returns {CommissioningServer} The created commissioning server.
1992
- */
1993
1741
  async createCommisioningServer(context, pluginName) {
1994
1742
  this.log.debug(`Creating matter commissioning server for plugin ${plg}${pluginName}${db}`);
1995
1743
  const deviceName = await context.get('deviceName');
1996
1744
  const deviceType = await context.get('deviceType');
1997
1745
  const vendorId = await context.get('vendorId');
1998
- const vendorName = await context.get('vendorName'); // Home app = Manufacturer
1746
+ const vendorName = await context.get('vendorName');
1999
1747
  const productId = await context.get('productId');
2000
- const productName = await context.get('productName'); // Home app = Model
1748
+ const productName = await context.get('productName');
2001
1749
  const serialNumber = await context.get('serialNumber');
2002
1750
  const uniqueId = await context.get('uniqueId');
2003
1751
  const softwareVersion = await context.get('softwareVersion', 1);
2004
- const softwareVersionString = await context.get('softwareVersionString', '1.0.0'); // Home app = Firmware Revision
1752
+ const softwareVersionString = await context.get('softwareVersionString', '1.0.0');
2005
1753
  const hardwareVersion = await context.get('hardwareVersion', 1);
2006
1754
  const hardwareVersionString = await context.get('hardwareVersionString', '1.0.0');
2007
1755
  this.log.debug(`Creating matter commissioning server for plugin ${plg}${pluginName}${db} with deviceName '${deviceName}' deviceType ${deviceType}(0x${deviceType.toString(16).padStart(4, '0')})`);
@@ -2009,7 +1757,6 @@ export class Matterbridge extends EventEmitter {
2009
1757
  this.log.debug(`Creating matter commissioning server for plugin ${plg}${pluginName}${db} with softwareVersion ${softwareVersion} softwareVersionString ${softwareVersionString}`);
2010
1758
  this.log.debug(`Creating matter commissioning server for plugin ${plg}${pluginName}${db} with hardwareVersion ${hardwareVersion} hardwareVersionString ${hardwareVersionString}`);
2011
1759
  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} `);
2012
- // Validate ipv4address
2013
1760
  if (this.ipv4address) {
2014
1761
  const networkInterfaces = os.networkInterfaces();
2015
1762
  const availableAddresses = Object.values(networkInterfaces)
@@ -2024,7 +1771,6 @@ export class Matterbridge extends EventEmitter {
2024
1771
  this.log.info(`Using ipv4address '${this.ipv4address}' for the Matter commissioning server.`);
2025
1772
  }
2026
1773
  }
2027
- // Validate ipv6address
2028
1774
  if (this.ipv6address) {
2029
1775
  const networkInterfaces = os.networkInterfaces();
2030
1776
  const availableAddresses = Object.values(networkInterfaces)
@@ -2055,7 +1801,7 @@ export class Matterbridge extends EventEmitter {
2055
1801
  nodeLabel: productName,
2056
1802
  productLabel: productName,
2057
1803
  softwareVersion,
2058
- softwareVersionString, // Home app = Firmware Revision
1804
+ softwareVersionString,
2059
1805
  hardwareVersion,
2060
1806
  hardwareVersionString,
2061
1807
  uniqueId,
@@ -2151,24 +1897,6 @@ export class Matterbridge extends EventEmitter {
2151
1897
  commissioningServer.addCommandHandler('testEventTrigger', async ({ request: { enableKey, eventTrigger } }) => this.log.info(`testEventTrigger called on GeneralDiagnostic cluster: ${enableKey} ${eventTrigger}`));
2152
1898
  return commissioningServer;
2153
1899
  }
2154
- /**
2155
- * Creates a commissioning server storage context.
2156
- *
2157
- * @param pluginName - The name of the plugin.
2158
- * @param deviceName - The name of the device.
2159
- * @param deviceType - The type of the device.
2160
- * @param vendorId - The vendor ID.
2161
- * @param vendorName - The vendor name.
2162
- * @param productId - The product ID.
2163
- * @param productName - The product name.
2164
- * @param serialNumber - The serial number of the device (optional).
2165
- * @param uniqueId - The unique ID of the device (optional).
2166
- * @param softwareVersion - The software version of the device (optional).
2167
- * @param softwareVersionString - The software version string of the device (optional).
2168
- * @param hardwareVersion - The hardware version of the device (optional).
2169
- * @param hardwareVersionString - The hardware version string of the device (optional).
2170
- * @returns The storage context for the commissioning server.
2171
- */
2172
1900
  async createCommissioningServerContext(pluginName, deviceName, deviceType, vendorId, vendorName, productId, productName) {
2173
1901
  if (!this.storageManager)
2174
1902
  throw new Error('No storage manager initialized');
@@ -2196,13 +1924,6 @@ export class Matterbridge extends EventEmitter {
2196
1924
  this.log.debug(`- hardwareVersion: ${await storageContext.get('hardwareVersion')} hardwareVersionString: ${await storageContext.get('hardwareVersionString')}`);
2197
1925
  return storageContext;
2198
1926
  }
2199
- /**
2200
- * Imports the commissioning server context for a specific plugin and device.
2201
- * @param pluginName - The name of the plugin.
2202
- * @param device - The MatterbridgeDevice object representing the device.
2203
- * @returns The commissioning server context.
2204
- * @throws Error if the BasicInformationCluster is not found.
2205
- */
2206
1927
  async importCommissioningServerContext(pluginName, device) {
2207
1928
  this.log.debug(`Importing matter commissioning server storage context from device for ${plg}${pluginName}${db}`);
2208
1929
  const basic = device.getClusterServer(BasicInformationCluster);
@@ -2237,14 +1958,6 @@ export class Matterbridge extends EventEmitter {
2237
1958
  this.log.debug(`- hardwareVersion: ${await storageContext.get('hardwareVersion')} hardwareVersionString: ${await storageContext.get('hardwareVersionString')}`);
2238
1959
  return storageContext;
2239
1960
  }
2240
- /**
2241
- * Shows the commissioning server QR code for a given plugin.
2242
- * @param {CommissioningServer} commissioningServer - The commissioning server instance.
2243
- * @param {StorageContext} storageContext - The storage context instance.
2244
- * @param {NodeStorage} nodeContext - The node storage instance.
2245
- * @param {string} pluginName - The name of the plugin of Matterbridge in bridge mode.
2246
- * @returns {Promise<void>} - A promise that resolves when the QR code is shown.
2247
- */
2248
1961
  async showCommissioningQRCode(commissioningServer, storageContext, nodeContext, pluginName) {
2249
1962
  if (!commissioningServer || !storageContext || !nodeContext || !pluginName) {
2250
1963
  this.log.error(`showCommissioningQRCode error: commissioningServer: ${!commissioningServer} storageContext: ${!storageContext} nodeContext: ${!nodeContext} pluginName: ${pluginName}`);
@@ -2255,8 +1968,7 @@ export class Matterbridge extends EventEmitter {
2255
1968
  const { qrPairingCode, manualPairingCode } = commissioningServer.getPairingCode();
2256
1969
  const QrCode = new QrCodeSchema();
2257
1970
  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`);
2258
- // eslint-disable-next-line no-console
2259
- if (this.log.logLevel === "debug" /* LogLevel.DEBUG */ || this.log.logLevel === "info" /* LogLevel.INFO */)
1971
+ if (this.log.logLevel === "debug" || this.log.logLevel === "info")
2260
1972
  console.log(`${QrCode.encode(qrPairingCode)}\n`);
2261
1973
  this.log.info(`${plg}${pluginName}${nf} \n\nqrPairingCode: ${qrPairingCode} \n\nManual pairing code: ${manualPairingCode}\n`);
2262
1974
  if (pluginName === 'Matterbridge') {
@@ -2303,12 +2015,6 @@ export class Matterbridge extends EventEmitter {
2303
2015
  }
2304
2016
  this.wssSendRefreshRequired();
2305
2017
  }
2306
- /**
2307
- * Sanitizes the fabric information by converting bigint properties to string cause res.json doesn't know bigint.
2308
- *
2309
- * @param fabricInfo - The array of exposed fabric information objects.
2310
- * @returns An array of sanitized exposed fabric information objects.
2311
- */
2312
2018
  sanitizeFabricInformations(fabricInfo) {
2313
2019
  return fabricInfo.map((info) => {
2314
2020
  return {
@@ -2322,12 +2028,6 @@ export class Matterbridge extends EventEmitter {
2322
2028
  };
2323
2029
  });
2324
2030
  }
2325
- /**
2326
- * Sanitizes the session information by converting bigint properties to string.
2327
- *
2328
- * @param sessionInfo - The array of session information objects.
2329
- * @returns An array of sanitized session information objects.
2330
- */
2331
2031
  sanitizeSessionInformation(sessionInfo) {
2332
2032
  return sessionInfo
2333
2033
  .filter((session) => session.isPeerActive)
@@ -2355,12 +2055,6 @@ export class Matterbridge extends EventEmitter {
2355
2055
  };
2356
2056
  });
2357
2057
  }
2358
- /**
2359
- * Sets the reachability of a commissioning server and trigger.
2360
- *
2361
- * @param {CommissioningServer} commissioningServer - The commissioning server to set the reachability for.
2362
- * @param {boolean} reachable - The new reachability status.
2363
- */
2364
2058
  setCommissioningServerReachability(commissioningServer, reachable) {
2365
2059
  const basicInformationCluster = commissioningServer?.getRootClusterServer(BasicInformationCluster);
2366
2060
  if (basicInformationCluster && basicInformationCluster.attributes.reachable !== undefined)
@@ -2368,11 +2062,6 @@ export class Matterbridge extends EventEmitter {
2368
2062
  if (basicInformationCluster && basicInformationCluster.triggerReachableChangedEvent)
2369
2063
  basicInformationCluster.triggerReachableChangedEvent({ reachableNewValue: reachable });
2370
2064
  }
2371
- /**
2372
- * Sets the reachability of the specified matter aggregator and its bridged devices and trigger.
2373
- * @param {Aggregator} matterAggregator - The matter aggregator to set the reachability for.
2374
- * @param {boolean} reachable - A boolean indicating the reachability status to set.
2375
- */
2376
2065
  setAggregatorReachability(matterAggregator, reachable) {
2377
2066
  const basicInformationCluster = matterAggregator.getClusterServer(BasicInformationCluster);
2378
2067
  if (basicInformationCluster && basicInformationCluster.attributes.reachable !== undefined)
@@ -2385,12 +2074,6 @@ export class Matterbridge extends EventEmitter {
2385
2074
  device.getClusterServer(BridgedDeviceBasicInformationCluster)?.triggerReachableChangedEvent({ reachableNewValue: reachable });
2386
2075
  });
2387
2076
  }
2388
- /**
2389
- * Sets the reachability of a device and trigger.
2390
- *
2391
- * @param {MatterbridgeDevice} device - The device to set the reachability for.
2392
- * @param {boolean} reachable - The new reachability status of the device.
2393
- */
2394
2077
  setDeviceReachability(device, reachable) {
2395
2078
  const basicInformationCluster = device.getClusterServer(BasicInformationCluster);
2396
2079
  if (basicInformationCluster && basicInformationCluster.attributes.reachable !== undefined)
@@ -2439,10 +2122,6 @@ export class Matterbridge extends EventEmitter {
2439
2122
  }
2440
2123
  return vendorName;
2441
2124
  };
2442
- /**
2443
- * Retrieves the base registered plugins sanitized for res.json().
2444
- * @returns {BaseRegisteredPlugin[]} A promise that resolves to an array of BaseRegisteredPlugin objects.
2445
- */
2446
2125
  async getBaseRegisteredPlugins() {
2447
2126
  const baseRegisteredPlugins = [];
2448
2127
  for (const plugin of this.plugins) {
@@ -2474,36 +2153,13 @@ export class Matterbridge extends EventEmitter {
2474
2153
  }
2475
2154
  return baseRegisteredPlugins;
2476
2155
  }
2477
- /**
2478
- * Spawns a child process with the given command and arguments.
2479
- * @param {string} command - The command to execute.
2480
- * @param {string[]} args - The arguments to pass to the command (default: []).
2481
- * @returns {Promise<boolean>} A promise that resolves when the child process exits successfully, or rejects if there is an error.
2482
- */
2483
2156
  async spawnCommand(command, args = []) {
2484
- /*
2485
- npm > npm.cmd on windows
2486
- cmd.exe ['dir'] on windows
2487
- await this.spawnCommand('npm', ['install', '-g', 'matterbridge']);
2488
- process.on('unhandledRejection', (reason, promise) => {
2489
- this.log.error('Unhandled Rejection at:', promise, 'reason:', reason);
2490
- });
2491
-
2492
- spawn - [14:27:21.125] [Matterbridge:spawn]: changed 38 packages in 4s
2493
- spawn - [14:27:21.125] [Matterbridge:spawn]: 10 packages are looking for funding run `npm fund` for details
2494
- debug - [14:27:21.131] [Matterbridge]: Child process exited with code 0 and signal null
2495
- debug - [14:27:21.131] [Matterbridge]: Child process stdio streams have closed with code 0
2496
- */
2497
2157
  const cmdLine = command + ' ' + args.join(' ');
2498
2158
  if (process.platform === 'win32' && command === 'npm') {
2499
- // Must be spawn('cmd.exe', ['/c', 'npm -g install <package>']);
2500
2159
  const argstring = 'npm ' + args.join(' ');
2501
2160
  args.splice(0, args.length, '/c', argstring);
2502
2161
  command = 'cmd.exe';
2503
2162
  }
2504
- // Decide when using sudo on linux
2505
- // When you need sudo: Spawn stderr: npm error Error: EACCES: permission denied
2506
- // When you don't need sudo: Failed to start child process "npm install -g matterbridge-eve-door": spawn sudo ENOENT
2507
2163
  if (hasParameter('sudo') || (process.platform === 'linux' && command === 'npm' && !hasParameter('docker') && !hasParameter('nosudo'))) {
2508
2164
  args.unshift(command);
2509
2165
  command = 'sudo';
@@ -2561,102 +2217,55 @@ export class Matterbridge extends EventEmitter {
2561
2217
  }
2562
2218
  });
2563
2219
  }
2564
- /**
2565
- * Sends a WebSocket message to all connected clients.
2566
- *
2567
- * @param {string} level - The logger level of the message: debug info notice warn error fatal...
2568
- * @param {string} time - The time string of the message
2569
- * @param {string} name - The logger name of the message
2570
- * @param {string} message - The content of the message.
2571
- */
2572
2220
  wssSendMessage(level, time, name, message) {
2573
2221
  if (!level || !time || !name || !message)
2574
2222
  return;
2575
- // Remove ANSI escape codes from the message
2576
- // eslint-disable-next-line no-control-regex
2577
2223
  message = message.replace(/\x1B\[[0-9;]*[m|s|u|K]/g, '');
2578
- // Remove leading asterisks from the message
2579
2224
  message = message.replace(/^\*+/, '');
2580
- // Replace all occurrences of \t and \n
2581
2225
  message = message.replace(/[\t\n]/g, '');
2582
- // Remove non-printable characters
2583
- // eslint-disable-next-line no-control-regex
2584
2226
  message = message.replace(/[\x00-\x1F\x7F]/g, '');
2585
- // Replace all occurrences of \" with "
2586
2227
  message = message.replace(/\\"/g, '"');
2587
- // Define the maximum allowed length for continuous characters without a space
2588
2228
  const maxContinuousLength = 100;
2589
2229
  const keepStartLength = 20;
2590
2230
  const keepEndLength = 20;
2591
- // Split the message into words
2592
2231
  message = message
2593
2232
  .split(' ')
2594
2233
  .map((word) => {
2595
- // If the word length exceeds the max continuous length, insert spaces and truncate
2596
2234
  if (word.length > maxContinuousLength) {
2597
2235
  return word.slice(0, keepStartLength) + ' ... ' + word.slice(-keepEndLength);
2598
2236
  }
2599
2237
  return word;
2600
2238
  })
2601
2239
  .join(' ');
2602
- // Send the message to all connected clients
2603
2240
  this.webSocketServer?.clients.forEach((client) => {
2604
2241
  if (client.readyState === WebSocket.OPEN) {
2605
2242
  client.send(JSON.stringify({ id: WS_ID_LOG, src: 'Matterbridge', level, time, name, message }));
2606
2243
  }
2607
2244
  });
2608
2245
  }
2609
- /**
2610
- * Sends a need to refresh WebSocket message to all connected clients.
2611
- *
2612
- */
2613
2246
  wssSendRefreshRequired() {
2614
2247
  this.matterbridgeInformation.refreshRequired = true;
2615
- // Send the message to all connected clients
2616
2248
  this.webSocketServer?.clients.forEach((client) => {
2617
2249
  if (client.readyState === WebSocket.OPEN) {
2618
2250
  client.send(JSON.stringify({ id: WS_ID_REFRESH_NEEDED, src: 'Matterbridge', dst: 'Matterbridge', method: 'refresh_required', params: {} }));
2619
2251
  }
2620
2252
  });
2621
2253
  }
2622
- /**
2623
- * Sends a need to restart WebSocket message to all connected clients.
2624
- *
2625
- */
2626
2254
  wssSendRestartRequired() {
2627
2255
  this.matterbridgeInformation.restartRequired = true;
2628
- // Send the message to all connected clients
2629
2256
  this.webSocketServer?.clients.forEach((client) => {
2630
2257
  if (client.readyState === WebSocket.OPEN) {
2631
2258
  client.send(JSON.stringify({ id: WS_ID_RESTART_NEEDED, src: 'Matterbridge', dst: 'Matterbridge', method: 'restart_required', params: {} }));
2632
2259
  }
2633
2260
  });
2634
2261
  }
2635
- /**
2636
- * Initializes the frontend of Matterbridge.
2637
- *
2638
- * @param port The port number to run the frontend server on. Default is 8283.
2639
- */
2640
2262
  async initializeFrontend(port = 8283) {
2641
2263
  let initializeError = false;
2642
2264
  this.log.debug(`Initializing the frontend ${hasParameter('ssl') ? 'https' : 'http'} server on port ${YELLOW}${port}${db}`);
2643
- // Create the express app that serves the frontend
2644
2265
  this.expressApp = express();
2645
- // Log all requests to the server for debugging
2646
- /*
2647
- if (hasParameter('homedir')) {
2648
- this.expressApp.use((req, res, next) => {
2649
- this.log.debug(`Received request on expressApp: ${req.method} ${req.url}`);
2650
- next();
2651
- });
2652
- }
2653
- */
2654
- // Serve static files from '/static' endpoint
2655
2266
  this.expressApp.use(express.static(path.join(this.rootDirectory, 'frontend/build')));
2656
2267
  if (!hasParameter('ssl')) {
2657
- // Create an HTTP server and attach the express app
2658
2268
  this.httpServer = createServer(this.expressApp);
2659
- // Listen on the specified port
2660
2269
  if (hasParameter('ingress')) {
2661
2270
  this.httpServer.listen(port, '0.0.0.0', () => {
2662
2271
  this.log.info(`The frontend http server is listening on ${UNDERLINE}http://0.0.0.0:${port}${UNDERLINEOFF}${rs}`);
@@ -2670,7 +2279,6 @@ export class Matterbridge extends EventEmitter {
2670
2279
  this.log.info(`The frontend http server is listening on ${UNDERLINE}http://[${this.systemInformation.ipv6Address}]:${port}${UNDERLINEOFF}${rs}`);
2671
2280
  });
2672
2281
  }
2673
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
2674
2282
  this.httpServer.on('error', (error) => {
2675
2283
  this.log.error(`Frontend http server error listening on ${port}`);
2676
2284
  switch (error.code) {
@@ -2686,7 +2294,6 @@ export class Matterbridge extends EventEmitter {
2686
2294
  });
2687
2295
  }
2688
2296
  else {
2689
- // Load the SSL certificate, the private key and optionally the CA certificate
2690
2297
  let cert;
2691
2298
  try {
2692
2299
  cert = await fs.readFile(path.join(this.matterbridgeDirectory, 'certs/cert.pem'), 'utf8');
@@ -2714,9 +2321,7 @@ export class Matterbridge extends EventEmitter {
2714
2321
  this.log.info(`CA certificate file ${path.join(this.matterbridgeDirectory, 'certs/ca.pem')} not loaded: ${error}`);
2715
2322
  }
2716
2323
  const serverOptions = { cert, key, ca };
2717
- // Create an HTTPS server with the SSL certificate and private key (ca is optional) and attach the express app
2718
2324
  this.httpsServer = https.createServer(serverOptions, this.expressApp);
2719
- // Listen on the specified port
2720
2325
  if (hasParameter('ingress')) {
2721
2326
  this.httpsServer.listen(port, '0.0.0.0', () => {
2722
2327
  this.log.info(`The frontend https server is listening on ${UNDERLINE}https://0.0.0.0:${port}${UNDERLINEOFF}${rs}`);
@@ -2730,7 +2335,6 @@ export class Matterbridge extends EventEmitter {
2730
2335
  this.log.info(`The frontend https server is listening on ${UNDERLINE}https://[${this.systemInformation.ipv6Address}]:${port}${UNDERLINEOFF}${rs}`);
2731
2336
  });
2732
2337
  }
2733
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
2734
2338
  this.httpsServer.on('error', (error) => {
2735
2339
  this.log.error(`Frontend https server error listening on ${port}`);
2736
2340
  switch (error.code) {
@@ -2747,13 +2351,12 @@ export class Matterbridge extends EventEmitter {
2747
2351
  }
2748
2352
  if (initializeError)
2749
2353
  return;
2750
- // Createe a WebSocket server and attach it to the http or https server
2751
2354
  const wssPort = port;
2752
2355
  const wssHost = hasParameter('ssl') ? `wss://${this.systemInformation.ipv4Address}:${wssPort}` : `ws://${this.systemInformation.ipv4Address}:${wssPort}`;
2753
2356
  this.webSocketServer = new WebSocketServer(hasParameter('ssl') ? { server: this.httpsServer } : { server: this.httpServer });
2754
2357
  this.webSocketServer.on('connection', (ws, request) => {
2755
2358
  const clientIp = request.socket.remoteAddress;
2756
- AnsiLogger.setGlobalCallback(this.wssSendMessage.bind(this), "debug" /* LogLevel.DEBUG */);
2359
+ AnsiLogger.setGlobalCallback(this.wssSendMessage.bind(this), "debug");
2757
2360
  this.log.info(`WebSocketServer client "${clientIp}" connected to Matterbridge`);
2758
2361
  ws.on('message', (message) => {
2759
2362
  this.log.debug(`WebSocket client message: ${message}`);
@@ -2786,7 +2389,6 @@ export class Matterbridge extends EventEmitter {
2786
2389
  this.webSocketServer.on('error', (ws, error) => {
2787
2390
  this.log.error(`WebSocketServer error: ${error}`);
2788
2391
  });
2789
- // Endpoint to validate login code
2790
2392
  this.expressApp.post('/api/login', express.json(), async (req, res) => {
2791
2393
  const { password } = req.body;
2792
2394
  this.log.debug('The frontend sent /api/login', password);
@@ -2805,14 +2407,12 @@ export class Matterbridge extends EventEmitter {
2805
2407
  this.log.warn('/api/login error wrong password');
2806
2408
  res.json({ valid: false });
2807
2409
  }
2808
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
2809
2410
  }
2810
2411
  catch (error) {
2811
2412
  this.log.error('/api/login error getting password');
2812
2413
  res.json({ valid: false });
2813
2414
  }
2814
2415
  });
2815
- // Endpoint to provide settings
2816
2416
  this.expressApp.get('/api/settings', express.json(), async (req, res) => {
2817
2417
  this.log.debug('The frontend sent /api/settings');
2818
2418
  this.matterbridgeInformation.bridgeMode = this.bridgeMode;
@@ -2833,17 +2433,13 @@ export class Matterbridge extends EventEmitter {
2833
2433
  this.matterbridgeInformation.matterbridgeSessionInformations = Array.from(this.matterbridgeSessionInformations.values());
2834
2434
  this.matterbridgeInformation.profile = this.profile;
2835
2435
  const response = { wssHost, ssl: hasParameter('ssl'), systemInformation: this.systemInformation, matterbridgeInformation: this.matterbridgeInformation };
2836
- // this.log.debug('Response:', debugStringify(response));
2837
2436
  res.json(response);
2838
2437
  });
2839
- // Endpoint to provide plugins
2840
2438
  this.expressApp.get('/api/plugins', async (req, res) => {
2841
2439
  this.log.debug('The frontend sent /api/plugins');
2842
2440
  const response = await this.getBaseRegisteredPlugins();
2843
- // this.log.debug('Response:', debugStringify(response));
2844
2441
  res.json(response);
2845
2442
  });
2846
- // Endpoint to provide devices
2847
2443
  this.expressApp.get('/api/devices', (req, res) => {
2848
2444
  this.log.debug('The frontend sent /api/devices');
2849
2445
  const devices = [];
@@ -2876,10 +2472,8 @@ export class Matterbridge extends EventEmitter {
2876
2472
  cluster: cluster,
2877
2473
  });
2878
2474
  });
2879
- // this.log.debug('Response:', debugStringify(data));
2880
2475
  res.json(devices);
2881
2476
  });
2882
- // Endpoint to provide the cluster servers of the devices
2883
2477
  this.expressApp.get('/api/devices_clusters/:selectedPluginName/:selectedDeviceEndpoint', (req, res) => {
2884
2478
  const selectedPluginName = req.params.selectedPluginName;
2885
2479
  const selectedDeviceEndpoint = parseInt(req.params.selectedDeviceEndpoint, 10);
@@ -2899,7 +2493,6 @@ export class Matterbridge extends EventEmitter {
2899
2493
  Object.entries(clusterServer.attributes).forEach(([key, value]) => {
2900
2494
  if (clusterServer.name === 'EveHistory')
2901
2495
  return;
2902
- // this.log.debug(`***--clusterServer: ${clusterServer.name}(${clusterServer.id}) attribute:${key}(${value.id}) ${value.isFixed} ${value.isWritable} ${value.isWritable}`);
2903
2496
  let attributeValue;
2904
2497
  try {
2905
2498
  if (typeof value.getLocal() === 'object')
@@ -2910,7 +2503,6 @@ export class Matterbridge extends EventEmitter {
2910
2503
  catch (error) {
2911
2504
  attributeValue = 'Fabric-Scoped';
2912
2505
  this.log.debug(`GetLocal value ${error} in clusterServer: ${clusterServer.name}(${clusterServer.id}) attribute: ${key}(${value.id})`);
2913
- // console.log(error);
2914
2506
  }
2915
2507
  data.push({
2916
2508
  endpoint: device.number ? device.number.toString() : '...',
@@ -2923,14 +2515,12 @@ export class Matterbridge extends EventEmitter {
2923
2515
  });
2924
2516
  });
2925
2517
  device.getChildEndpoints().forEach((childEndpoint) => {
2926
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
2927
2518
  const name = this.edge ? childEndpoint.endpoint?.id : childEndpoint.uniqueStorageKey;
2928
2519
  const clusterServers = childEndpoint.getAllClusterServers();
2929
2520
  clusterServers.forEach((clusterServer) => {
2930
2521
  Object.entries(clusterServer.attributes).forEach(([key, value]) => {
2931
2522
  if (clusterServer.name === 'EveHistory')
2932
2523
  return;
2933
- // this.log.debug(`***--clusterServer: ${clusterServer.name}(${clusterServer.id}) attribute:${key}(${value.id}) ${value.isFixed} ${value.isWritable} ${value.isWritable}`);
2934
2524
  let attributeValue;
2935
2525
  try {
2936
2526
  if (typeof value.getLocal() === 'object')
@@ -2941,7 +2531,6 @@ export class Matterbridge extends EventEmitter {
2941
2531
  catch (error) {
2942
2532
  attributeValue = 'Unavailable';
2943
2533
  this.log.debug(`GetLocal error ${error} in clusterServer: ${clusterServer.name}(${clusterServer.id}) attribute: ${key}(${value.id})`);
2944
- // console.log(error);
2945
2534
  }
2946
2535
  data.push({
2947
2536
  endpoint: (childEndpoint.number ? childEndpoint.number.toString() : '...') + (name ? ' (' + name + ')' : ''),
@@ -2958,7 +2547,6 @@ export class Matterbridge extends EventEmitter {
2958
2547
  });
2959
2548
  res.json(data);
2960
2549
  });
2961
- // Endpoint to view the log
2962
2550
  this.expressApp.get('/api/view-log', async (req, res) => {
2963
2551
  this.log.debug('The frontend sent /api/log');
2964
2552
  try {
@@ -2971,12 +2559,10 @@ export class Matterbridge extends EventEmitter {
2971
2559
  res.status(500).send('Error reading log file');
2972
2560
  }
2973
2561
  });
2974
- // Endpoint to download the matterbridge log
2975
2562
  this.expressApp.get('/api/download-mblog', async (req, res) => {
2976
2563
  this.log.debug('The frontend sent /api/download-mblog');
2977
2564
  try {
2978
2565
  await fs.access(path.join(this.matterbridgeDirectory, this.matterbrideLoggerFile), fs.constants.F_OK);
2979
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
2980
2566
  }
2981
2567
  catch (error) {
2982
2568
  fs.appendFile(path.join(this.matterbridgeDirectory, this.matterbrideLoggerFile), 'Enable the log on file in the settings to enable the file logger');
@@ -2988,12 +2574,10 @@ export class Matterbridge extends EventEmitter {
2988
2574
  }
2989
2575
  });
2990
2576
  });
2991
- // Endpoint to download the matter log
2992
2577
  this.expressApp.get('/api/download-mjlog', async (req, res) => {
2993
2578
  this.log.debug('The frontend sent /api/download-mjlog');
2994
2579
  try {
2995
2580
  await fs.access(path.join(this.matterbridgeDirectory, this.matterLoggerFile), fs.constants.F_OK);
2996
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
2997
2581
  }
2998
2582
  catch (error) {
2999
2583
  fs.appendFile(path.join(this.matterbridgeDirectory, this.matterLoggerFile), 'Enable the log on file in the settings to enable the file logger');
@@ -3005,7 +2589,6 @@ export class Matterbridge extends EventEmitter {
3005
2589
  }
3006
2590
  });
3007
2591
  });
3008
- // Endpoint to download the matter storage file
3009
2592
  this.expressApp.get('/api/download-mjstorage', (req, res) => {
3010
2593
  this.log.debug('The frontend sent /api/download-mjstorage');
3011
2594
  res.download(path.join(this.matterbridgeDirectory, this.matterStorageName), 'matterbridge.json', (error) => {
@@ -3015,7 +2598,6 @@ export class Matterbridge extends EventEmitter {
3015
2598
  }
3016
2599
  });
3017
2600
  });
3018
- // Endpoint to download the matterbridge storage directory
3019
2601
  this.expressApp.get('/api/download-mbstorage', async (req, res) => {
3020
2602
  this.log.debug('The frontend sent /api/download-mbstorage');
3021
2603
  await createZip(path.join(os.tmpdir(), `matterbridge.${this.nodeStorageName}.zip`), path.join(this.matterbridgeDirectory, this.nodeStorageName));
@@ -3026,7 +2608,6 @@ export class Matterbridge extends EventEmitter {
3026
2608
  }
3027
2609
  });
3028
2610
  });
3029
- // Endpoint to download the matterbridge plugin directory
3030
2611
  this.expressApp.get('/api/download-pluginstorage', async (req, res) => {
3031
2612
  this.log.debug('The frontend sent /api/download-pluginstorage');
3032
2613
  await createZip(path.join(os.tmpdir(), `matterbridge.pluginstorage.zip`), this.matterbridgePluginDirectory);
@@ -3037,11 +2618,9 @@ export class Matterbridge extends EventEmitter {
3037
2618
  }
3038
2619
  });
3039
2620
  });
3040
- // Endpoint to download the matterbridge plugin config files
3041
2621
  this.expressApp.get('/api/download-pluginconfig', async (req, res) => {
3042
2622
  this.log.debug('The frontend sent /api/download-pluginconfig');
3043
2623
  await createZip(path.join(os.tmpdir(), `matterbridge.pluginconfig.zip`), path.relative(process.cwd(), path.join(this.matterbridgeDirectory, '*.config.json')));
3044
- // 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')));
3045
2624
  res.download(path.join(os.tmpdir(), `matterbridge.pluginconfig.zip`), `matterbridge.pluginconfig.zip`, (error) => {
3046
2625
  if (error) {
3047
2626
  this.log.error(`Error downloading file matterbridge.pluginstorage.zip: ${error instanceof Error ? error.message : error}`);
@@ -3049,7 +2628,6 @@ export class Matterbridge extends EventEmitter {
3049
2628
  }
3050
2629
  });
3051
2630
  });
3052
- // Endpoint to download the matterbridge plugin config files
3053
2631
  this.expressApp.get('/api/download-backup', async (req, res) => {
3054
2632
  this.log.debug('The frontend sent /api/download-backup');
3055
2633
  res.download(path.join(os.tmpdir(), `matterbridge.backup.zip`), `matterbridge.backup.zip`, (error) => {
@@ -3059,7 +2637,6 @@ export class Matterbridge extends EventEmitter {
3059
2637
  }
3060
2638
  });
3061
2639
  });
3062
- // Endpoint to receive commands
3063
2640
  this.expressApp.post('/api/command/:command/:param', express.json(), async (req, res) => {
3064
2641
  const command = req.params.command;
3065
2642
  let param = req.params.param;
@@ -3069,15 +2646,13 @@ export class Matterbridge extends EventEmitter {
3069
2646
  return;
3070
2647
  }
3071
2648
  this.log.debug(`Received frontend command: ${command}:${param}`);
3072
- // Handle the command setpassword from Settings
3073
2649
  if (command === 'setpassword') {
3074
- const password = param.slice(1, -1); // Remove the first and last characters
2650
+ const password = param.slice(1, -1);
3075
2651
  this.log.debug('setpassword', param, password);
3076
2652
  await this.nodeContext?.set('password', password);
3077
2653
  res.json({ message: 'Command received' });
3078
2654
  return;
3079
2655
  }
3080
- // Handle the command setbridgemode from Settings
3081
2656
  if (command === 'setbridgemode') {
3082
2657
  this.log.debug(`setbridgemode: ${param}`);
3083
2658
  this.wssSendRestartRequired();
@@ -3085,7 +2660,6 @@ export class Matterbridge extends EventEmitter {
3085
2660
  res.json({ message: 'Command received' });
3086
2661
  return;
3087
2662
  }
3088
- // Handle the command backup from Settings
3089
2663
  if (command === 'backup') {
3090
2664
  this.log.notice(`Prepairing the backup...`);
3091
2665
  await createZip(path.join(os.tmpdir(), `matterbridge.backup.zip`), path.join(this.matterbridgeDirectory), path.join(this.matterbridgePluginDirectory));
@@ -3093,26 +2667,25 @@ export class Matterbridge extends EventEmitter {
3093
2667
  res.json({ message: 'Command received' });
3094
2668
  return;
3095
2669
  }
3096
- // Handle the command setmbloglevel from Settings
3097
2670
  if (command === 'setmbloglevel') {
3098
2671
  this.log.debug('Matterbridge log level:', param);
3099
2672
  if (param === 'Debug') {
3100
- this.log.logLevel = "debug" /* LogLevel.DEBUG */;
2673
+ this.log.logLevel = "debug";
3101
2674
  }
3102
2675
  else if (param === 'Info') {
3103
- this.log.logLevel = "info" /* LogLevel.INFO */;
2676
+ this.log.logLevel = "info";
3104
2677
  }
3105
2678
  else if (param === 'Notice') {
3106
- this.log.logLevel = "notice" /* LogLevel.NOTICE */;
2679
+ this.log.logLevel = "notice";
3107
2680
  }
3108
2681
  else if (param === 'Warn') {
3109
- this.log.logLevel = "warn" /* LogLevel.WARN */;
2682
+ this.log.logLevel = "warn";
3110
2683
  }
3111
2684
  else if (param === 'Error') {
3112
- this.log.logLevel = "error" /* LogLevel.ERROR */;
2685
+ this.log.logLevel = "error";
3113
2686
  }
3114
2687
  else if (param === 'Fatal') {
3115
- this.log.logLevel = "fatal" /* LogLevel.FATAL */;
2688
+ this.log.logLevel = "fatal";
3116
2689
  }
3117
2690
  await this.nodeContext?.set('matterbridgeLogLevel', this.log.logLevel);
3118
2691
  MatterbridgeDevice.logLevel = this.log.logLevel;
@@ -3120,13 +2693,12 @@ export class Matterbridge extends EventEmitter {
3120
2693
  for (const plugin of this.plugins) {
3121
2694
  if (!plugin.platform || !plugin.platform.config)
3122
2695
  continue;
3123
- plugin.platform.log.logLevel = plugin.platform.config.debug ? "debug" /* LogLevel.DEBUG */ : this.log.logLevel;
3124
- await plugin.platform.onChangeLoggerLevel(plugin.platform.config.debug ? "debug" /* LogLevel.DEBUG */ : this.log.logLevel);
2696
+ plugin.platform.log.logLevel = plugin.platform.config.debug ? "debug" : this.log.logLevel;
2697
+ await plugin.platform.onChangeLoggerLevel(plugin.platform.config.debug ? "debug" : this.log.logLevel);
3125
2698
  }
3126
2699
  res.json({ message: 'Command received' });
3127
2700
  return;
3128
2701
  }
3129
- // Handle the command setmbloglevel from Settings
3130
2702
  if (command === 'setmjloglevel') {
3131
2703
  this.log.debug('Matter.js log level:', param);
3132
2704
  if (param === 'Debug') {
@@ -3151,34 +2723,30 @@ export class Matterbridge extends EventEmitter {
3151
2723
  res.json({ message: 'Command received' });
3152
2724
  return;
3153
2725
  }
3154
- // Handle the command setmdnsinterface from Settings
3155
2726
  if (command === 'setmdnsinterface') {
3156
- param = param.slice(1, -1); // Remove the first and last characters *mdns*
2727
+ param = param.slice(1, -1);
3157
2728
  this.matterbridgeInformation.mattermdnsinterface = param;
3158
2729
  this.log.debug('Matter.js mdns interface:', param === '' ? 'All interfaces' : param);
3159
2730
  await this.nodeContext?.set('mattermdnsinterface', param);
3160
2731
  res.json({ message: 'Command received' });
3161
2732
  return;
3162
2733
  }
3163
- // Handle the command setipv4address from Settings
3164
2734
  if (command === 'setipv4address') {
3165
- param = param.slice(1, -1); // Remove the first and last characters *ip*
2735
+ param = param.slice(1, -1);
3166
2736
  this.matterbridgeInformation.matteripv4address = param;
3167
2737
  this.log.debug('Matter.js ipv4 address:', param === '' ? 'All ipv4 addresses' : param);
3168
2738
  await this.nodeContext?.set('matteripv4address', param);
3169
2739
  res.json({ message: 'Command received' });
3170
2740
  return;
3171
2741
  }
3172
- // Handle the command setipv6address from Settings
3173
2742
  if (command === 'setipv6address') {
3174
- param = param.slice(1, -1); // Remove the first and last characters *ip*
2743
+ param = param.slice(1, -1);
3175
2744
  this.matterbridgeInformation.matteripv6address = param;
3176
2745
  this.log.debug('Matter.js ipv6 address:', param === '' ? 'All ipv6 addresses' : param);
3177
2746
  await this.nodeContext?.set('matteripv6address', param);
3178
2747
  res.json({ message: 'Command received' });
3179
2748
  return;
3180
2749
  }
3181
- // Handle the command setmatterport from Settings
3182
2750
  if (command === 'setmatterport') {
3183
2751
  const port = Math.min(Math.max(parseInt(param), 5540), 5560);
3184
2752
  this.matterbridgeInformation.matterPort = port;
@@ -3187,7 +2755,6 @@ export class Matterbridge extends EventEmitter {
3187
2755
  res.json({ message: 'Command received' });
3188
2756
  return;
3189
2757
  }
3190
- // Handle the command setmatterdiscriminator from Settings
3191
2758
  if (command === 'setmatterdiscriminator') {
3192
2759
  const discriminator = Math.min(Math.max(parseInt(param), 1000), 4095);
3193
2760
  this.matterbridgeInformation.matterDiscriminator = discriminator;
@@ -3196,7 +2763,6 @@ export class Matterbridge extends EventEmitter {
3196
2763
  res.json({ message: 'Command received' });
3197
2764
  return;
3198
2765
  }
3199
- // Handle the command setmatterpasscode from Settings
3200
2766
  if (command === 'setmatterpasscode') {
3201
2767
  const passcode = Math.min(Math.max(parseInt(param), 10000000), 90000000);
3202
2768
  this.matterbridgeInformation.matterPasscode = passcode;
@@ -3205,20 +2771,17 @@ export class Matterbridge extends EventEmitter {
3205
2771
  res.json({ message: 'Command received' });
3206
2772
  return;
3207
2773
  }
3208
- // Handle the command setmbloglevel from Settings
3209
2774
  if (command === 'setmblogfile') {
3210
2775
  this.log.debug('Matterbridge file log:', param);
3211
2776
  this.matterbridgeInformation.fileLogger = param === 'true';
3212
2777
  await this.nodeContext?.set('matterbridgeFileLog', param === 'true');
3213
- // Create the file logger for matterbridge
3214
2778
  if (param === 'true')
3215
- AnsiLogger.setGlobalLogfile(path.join(this.matterbridgeDirectory, this.matterbrideLoggerFile), "debug" /* LogLevel.DEBUG */, true);
2779
+ AnsiLogger.setGlobalLogfile(path.join(this.matterbridgeDirectory, this.matterbrideLoggerFile), "debug", true);
3216
2780
  else
3217
2781
  AnsiLogger.setGlobalLogfile(undefined);
3218
2782
  res.json({ message: 'Command received' });
3219
2783
  return;
3220
2784
  }
3221
- // Handle the command setmbloglevel from Settings
3222
2785
  if (command === 'setmjlogfile') {
3223
2786
  this.log.debug('Matter file log:', param);
3224
2787
  this.matterbridgeInformation.matterFileLogger = param === 'true';
@@ -3245,43 +2808,36 @@ export class Matterbridge extends EventEmitter {
3245
2808
  res.json({ message: 'Command received' });
3246
2809
  return;
3247
2810
  }
3248
- // Handle the command unregister from Settings
3249
2811
  if (command === 'unregister') {
3250
2812
  await this.unregisterAndShutdownProcess();
3251
2813
  res.json({ message: 'Command received' });
3252
2814
  return;
3253
2815
  }
3254
- // Handle the command reset from Settings
3255
2816
  if (command === 'reset') {
3256
2817
  await this.shutdownProcessAndReset();
3257
2818
  res.json({ message: 'Command received' });
3258
2819
  return;
3259
2820
  }
3260
- // Handle the command factoryreset from Settings
3261
2821
  if (command === 'factoryreset') {
3262
2822
  await this.shutdownProcessAndFactoryReset();
3263
2823
  res.json({ message: 'Command received' });
3264
2824
  return;
3265
2825
  }
3266
- // Handle the command shutdown from Header
3267
2826
  if (command === 'shutdown') {
3268
2827
  await this.shutdownProcess();
3269
2828
  res.json({ message: 'Command received' });
3270
2829
  return;
3271
2830
  }
3272
- // Handle the command restart from Header
3273
2831
  if (command === 'restart') {
3274
2832
  await this.restartProcess();
3275
2833
  res.json({ message: 'Command received' });
3276
2834
  return;
3277
2835
  }
3278
- // Handle the command update from Header
3279
2836
  if (command === 'update') {
3280
2837
  this.log.info('Updating matterbridge...');
3281
2838
  try {
3282
2839
  await this.spawnCommand('npm', ['install', '-g', 'matterbridge', '--omit=dev', '--verbose']);
3283
2840
  this.log.info('Matterbridge has been updated. Full restart required.');
3284
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
3285
2841
  }
3286
2842
  catch (error) {
3287
2843
  this.log.error('Error updating matterbridge');
@@ -3291,11 +2847,9 @@ export class Matterbridge extends EventEmitter {
3291
2847
  res.json({ message: 'Command received' });
3292
2848
  return;
3293
2849
  }
3294
- // Handle the command saveconfig from Home
3295
2850
  if (command === 'saveconfig') {
3296
2851
  param = param.replace(/\*/g, '\\');
3297
2852
  this.log.info(`Saving config for plugin ${plg}${param}${nf}...`);
3298
- // console.log('Req.body:', JSON.stringify(req.body, null, 2));
3299
2853
  if (!this.plugins.has(param)) {
3300
2854
  this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
3301
2855
  }
@@ -3309,39 +2863,33 @@ export class Matterbridge extends EventEmitter {
3309
2863
  res.json({ message: 'Command received' });
3310
2864
  return;
3311
2865
  }
3312
- // Handle the command installplugin from Home
3313
2866
  if (command === 'installplugin') {
3314
2867
  param = param.replace(/\*/g, '\\');
3315
2868
  this.log.info(`Installing plugin ${plg}${param}${nf}...`);
3316
2869
  try {
3317
2870
  await this.spawnCommand('npm', ['install', '-g', param, '--omit=dev', '--verbose']);
3318
2871
  this.log.info(`Plugin ${plg}${param}${nf} installed. Full restart required.`);
3319
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
3320
2872
  }
3321
2873
  catch (error) {
3322
2874
  this.log.error(`Error installing plugin ${plg}${param}${er}`);
3323
2875
  }
3324
2876
  this.wssSendRestartRequired();
3325
2877
  param = param.split('@')[0];
3326
- // Also add the plugin to matterbridge so no return!
3327
2878
  if (param === 'matterbridge') {
3328
- // 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
3329
2879
  res.json({ message: 'Command received' });
3330
2880
  return;
3331
2881
  }
3332
2882
  }
3333
- // Handle the command addplugin from Home
3334
2883
  if (command === 'addplugin' || command === 'installplugin') {
3335
2884
  param = param.replace(/\*/g, '\\');
3336
2885
  const plugin = await this.plugins.add(param);
3337
2886
  if (plugin) {
3338
- this.plugins.load(plugin, true, 'The plugin has been added', true); // No await do it in the background
2887
+ this.plugins.load(plugin, true, 'The plugin has been added', true);
3339
2888
  }
3340
2889
  res.json({ message: 'Command received' });
3341
2890
  this.wssSendRefreshRequired();
3342
2891
  return;
3343
2892
  }
3344
- // Handle the command removeplugin from Home
3345
2893
  if (command === 'removeplugin') {
3346
2894
  if (!this.plugins.has(param)) {
3347
2895
  this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
@@ -3355,7 +2903,6 @@ export class Matterbridge extends EventEmitter {
3355
2903
  this.wssSendRefreshRequired();
3356
2904
  return;
3357
2905
  }
3358
- // Handle the command enableplugin from Home
3359
2906
  if (command === 'enableplugin') {
3360
2907
  if (!this.plugins.has(param)) {
3361
2908
  this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
@@ -3373,14 +2920,13 @@ export class Matterbridge extends EventEmitter {
3373
2920
  plugin.registeredDevices = undefined;
3374
2921
  plugin.addedDevices = undefined;
3375
2922
  await this.plugins.enable(param);
3376
- this.plugins.load(plugin, true, 'The plugin has been enabled', true); // No await do it in the background
2923
+ this.plugins.load(plugin, true, 'The plugin has been enabled', true);
3377
2924
  }
3378
2925
  }
3379
2926
  res.json({ message: 'Command received' });
3380
2927
  this.wssSendRefreshRequired();
3381
2928
  return;
3382
2929
  }
3383
- // Handle the command disableplugin from Home
3384
2930
  if (command === 'disableplugin') {
3385
2931
  if (!this.plugins.has(param)) {
3386
2932
  this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
@@ -3397,7 +2943,6 @@ export class Matterbridge extends EventEmitter {
3397
2943
  return;
3398
2944
  }
3399
2945
  });
3400
- // Fallback for routing (must be the last route)
3401
2946
  this.expressApp.get('*', (req, res) => {
3402
2947
  this.log.debug('The frontend sent:', req.url);
3403
2948
  this.log.debug('Response send file:', path.join(this.rootDirectory, 'frontend/build/index.html'));
@@ -3405,11 +2950,6 @@ export class Matterbridge extends EventEmitter {
3405
2950
  });
3406
2951
  this.log.debug(`Frontend initialized on port ${YELLOW}${port}${db} static ${UNDERLINE}${path.join(this.rootDirectory, 'frontend/build')}${UNDERLINEOFF}${rs}`);
3407
2952
  }
3408
- /**
3409
- * Retrieves the cluster text description from a given device.
3410
- * @param {MatterbridgeDevice} device - The MatterbridgeDevice object.
3411
- * @returns {string} The attributes description of the cluster servers in the device.
3412
- */
3413
2953
  getClusterTextFromDevice(device) {
3414
2954
  const stringifyUserLabel = (endpoint) => {
3415
2955
  const labelList = endpoint.getClusterServer(UserLabelCluster)?.attributes.labelList.getLocal();
@@ -3432,11 +2972,9 @@ export class Matterbridge extends EventEmitter {
3432
2972
  return '';
3433
2973
  };
3434
2974
  let attributes = '';
3435
- // this.log.debug(`***getClusterTextFromDevice: ${device.deviceName} (${device.name})`);
3436
2975
  const clusterServers = device.getAllClusterServers();
3437
2976
  clusterServers.forEach((clusterServer) => {
3438
2977
  try {
3439
- // this.log.debug(`**--clusterServer: ${clusterServer.id} (${clusterServer.name})`);
3440
2978
  if (clusterServer.name === 'OnOff')
3441
2979
  attributes += `OnOff: ${clusterServer.attributes.onOff.getLocal()} `;
3442
2980
  if (clusterServer.name === 'Switch')
@@ -3487,30 +3025,18 @@ export class Matterbridge extends EventEmitter {
3487
3025
  attributes += `${stringifyFixedLabel(device)} `;
3488
3026
  if (clusterServer.name === 'UserLabel')
3489
3027
  attributes += `${stringifyUserLabel(device)} `;
3490
- // this.log.debug(`*--clusterServer: ${clusterServer.id} (${clusterServer.name})`);
3491
3028
  }
3492
3029
  catch (error) {
3493
3030
  this.log.error(`getClusterTextFromDevice with ${clusterServer.name} error: ${error}`);
3494
3031
  }
3495
3032
  });
3496
- // this.log.debug(`*getClusterTextFromDevice: ${device.deviceName} (${device.name})`);
3497
3033
  return attributes;
3498
3034
  }
3499
- /**
3500
- * Initializes the Matterbridge instance as extension for zigbee2mqtt.
3501
- * @deprecated This method is deprecated and will be removed in a future version.
3502
- *
3503
- * @returns A Promise that resolves when the initialization is complete.
3504
- */
3505
3035
  async startExtension(dataPath, extensionVersion, port = 5540) {
3506
- // Set the bridge mode
3507
3036
  this.bridgeMode = 'bridge';
3508
- // Set the first port to use
3509
3037
  this.port = port;
3510
- // Set Matterbridge logger
3511
- this.log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: "info" /* LogLevel.INFO */ });
3038
+ this.log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4, logLevel: "info" });
3512
3039
  this.log.debug('Matterbridge extension is starting...');
3513
- // Initialize NodeStorage
3514
3040
  this.matterbridgeDirectory = dataPath;
3515
3041
  this.log.debug('Creating node storage manager dir: ' + path.join(this.matterbridgeDirectory, 'node_storage'));
3516
3042
  this.nodeStorage = new NodeStorageManager({ dir: path.join(this.matterbridgeDirectory, 'node_storage'), logging: false });
@@ -3529,13 +3055,10 @@ export class Matterbridge extends EventEmitter {
3529
3055
  };
3530
3056
  this.plugins.set(plugin);
3531
3057
  this.plugins.saveToStorage();
3532
- // Log system info and create .matterbridge directory
3533
3058
  await this.logNodeAndSystemInfo();
3534
3059
  this.matterbridgeDirectory = dataPath;
3535
- // Set matter.js logger level and format
3536
3060
  Logger.defaultLogLevel = MatterLogLevel.INFO;
3537
3061
  Logger.format = MatterLogFormat.ANSI;
3538
- // Start the storage and create matterbridgeContext
3539
3062
  await this.startMatterStorage('json', path.join(this.matterbridgeDirectory, this.matterStorageName));
3540
3063
  if (!this.storageManager)
3541
3064
  return false;
@@ -3545,7 +3068,7 @@ export class Matterbridge extends EventEmitter {
3545
3068
  await this.matterbridgeContext.set('softwareVersion', 1);
3546
3069
  await this.matterbridgeContext.set('softwareVersionString', this.matterbridgeVersion);
3547
3070
  await this.matterbridgeContext.set('hardwareVersion', 1);
3548
- await this.matterbridgeContext.set('hardwareVersionString', extensionVersion); // Update with the extension version
3071
+ await this.matterbridgeContext.set('hardwareVersionString', extensionVersion);
3549
3072
  this.matterServer = this.createMatterServer(this.storageManager);
3550
3073
  this.log.debug(`Creating commissioning server for ${plg}Matterbridge${db}`);
3551
3074
  this.commissioningServer = await this.createCommisioningServer(this.matterbridgeContext, 'Matterbridge');
@@ -3558,7 +3081,6 @@ export class Matterbridge extends EventEmitter {
3558
3081
  await this.startMatterServer();
3559
3082
  this.log.info('Matter server started');
3560
3083
  await this.showCommissioningQRCode(this.commissioningServer, this.matterbridgeContext, this.nodeContext, 'Matterbridge');
3561
- // Set reachability to true and trigger event after 60 seconds
3562
3084
  setTimeout(() => {
3563
3085
  this.log.info(`Setting reachability to true for ${plg}Matterbridge${db}`);
3564
3086
  if (this.commissioningServer)
@@ -3568,31 +3090,14 @@ export class Matterbridge extends EventEmitter {
3568
3090
  }, 60 * 1000);
3569
3091
  return this.commissioningServer.isCommissioned();
3570
3092
  }
3571
- /**
3572
- * Close the Matterbridge instance as extension for zigbee2mqtt.
3573
- * @deprecated This method is deprecated and will be removed in a future version.
3574
- *
3575
- * @returns A Promise that resolves when the initialization is complete.
3576
- */
3577
3093
  async stopExtension() {
3578
- // Closing matter
3579
3094
  await this.stopMatterServer();
3580
- // Clearing the session manager
3581
- // this.matterbridgeContext?.createContext('SessionManager').clear();
3582
- // Closing storage
3583
3095
  await this.stopMatterStorage();
3584
3096
  this.log.info('Matter server stopped');
3585
3097
  }
3586
- /**
3587
- * Checks if the extension is commissioned.
3588
- * @deprecated This method is deprecated and will be removed in a future version.
3589
- *
3590
- * @returns {boolean} Returns true if the extension is commissioned, false otherwise.
3591
- */
3592
3098
  isExtensionCommissioned() {
3593
3099
  if (!this.commissioningServer)
3594
3100
  return false;
3595
3101
  return this.commissioningServer.isCommissioned();
3596
3102
  }
3597
3103
  }
3598
- //# sourceMappingURL=matterbridge.js.map