matterbridge 1.7.1 → 1.7.2-dev.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/dist/cli.js +0 -26
  3. package/dist/cluster/export.js +0 -2
  4. package/dist/defaultConfigSchema.js +0 -23
  5. package/dist/deviceManager.js +1 -26
  6. package/dist/index.js +0 -30
  7. package/dist/logger/export.js +0 -1
  8. package/dist/matter/export.js +0 -4
  9. package/dist/matterbridge.js +61 -707
  10. package/dist/matterbridgeAccessoryPlatform.js +0 -33
  11. package/dist/matterbridgeBehaviors.js +1 -29
  12. package/dist/matterbridgeDevice.js +9 -996
  13. package/dist/matterbridgeDeviceTypes.js +11 -82
  14. package/dist/matterbridgeDynamicPlatform.js +0 -33
  15. package/dist/matterbridgeEdge.js +0 -530
  16. package/dist/matterbridgeEndpoint.js +14 -1121
  17. package/dist/matterbridgePlatform.js +7 -112
  18. package/dist/matterbridgeTypes.js +0 -24
  19. package/dist/matterbridgeWebsocket.js +14 -46
  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/frontend/build/asset-manifest.json +6 -6
  26. package/frontend/build/index.html +1 -1
  27. package/frontend/build/static/css/{main.b1a621ee.css → main.18f673b9.css} +2 -2
  28. package/frontend/build/static/css/main.18f673b9.css.map +1 -0
  29. package/frontend/build/static/js/{main.ecd94d17.js → main.688f9551.js} +4 -4
  30. package/frontend/build/static/js/main.688f9551.js.map +1 -0
  31. package/npm-shrinkwrap.json +2 -2
  32. package/package.json +1 -2
  33. package/dist/cli.d.ts +0 -25
  34. package/dist/cli.d.ts.map +0 -1
  35. package/dist/cli.js.map +0 -1
  36. package/dist/cluster/export.d.ts +0 -2
  37. package/dist/cluster/export.d.ts.map +0 -1
  38. package/dist/cluster/export.js.map +0 -1
  39. package/dist/defaultConfigSchema.d.ts +0 -27
  40. package/dist/defaultConfigSchema.d.ts.map +0 -1
  41. package/dist/defaultConfigSchema.js.map +0 -1
  42. package/dist/deviceManager.d.ts +0 -46
  43. package/dist/deviceManager.d.ts.map +0 -1
  44. package/dist/deviceManager.js.map +0 -1
  45. package/dist/index.d.ts +0 -40
  46. package/dist/index.d.ts.map +0 -1
  47. package/dist/index.js.map +0 -1
  48. package/dist/logger/export.d.ts +0 -2
  49. package/dist/logger/export.d.ts.map +0 -1
  50. package/dist/logger/export.js.map +0 -1
  51. package/dist/matter/export.d.ts +0 -11
  52. package/dist/matter/export.d.ts.map +0 -1
  53. package/dist/matter/export.js.map +0 -1
  54. package/dist/matterbridge.d.ts +0 -483
  55. package/dist/matterbridge.d.ts.map +0 -1
  56. package/dist/matterbridge.js.map +0 -1
  57. package/dist/matterbridgeAccessoryPlatform.d.ts +0 -39
  58. package/dist/matterbridgeAccessoryPlatform.d.ts.map +0 -1
  59. package/dist/matterbridgeAccessoryPlatform.js.map +0 -1
  60. package/dist/matterbridgeBehaviors.d.ts +0 -942
  61. package/dist/matterbridgeBehaviors.d.ts.map +0 -1
  62. package/dist/matterbridgeBehaviors.js.map +0 -1
  63. package/dist/matterbridgeDevice.d.ts +0 -7077
  64. package/dist/matterbridgeDevice.d.ts.map +0 -1
  65. package/dist/matterbridgeDevice.js.map +0 -1
  66. package/dist/matterbridgeDeviceTypes.d.ts +0 -109
  67. package/dist/matterbridgeDeviceTypes.d.ts.map +0 -1
  68. package/dist/matterbridgeDeviceTypes.js.map +0 -1
  69. package/dist/matterbridgeDynamicPlatform.d.ts +0 -39
  70. package/dist/matterbridgeDynamicPlatform.d.ts.map +0 -1
  71. package/dist/matterbridgeDynamicPlatform.js.map +0 -1
  72. package/dist/matterbridgeEdge.d.ts +0 -91
  73. package/dist/matterbridgeEdge.d.ts.map +0 -1
  74. package/dist/matterbridgeEdge.js.map +0 -1
  75. package/dist/matterbridgeEndpoint.d.ts +0 -10151
  76. package/dist/matterbridgeEndpoint.d.ts.map +0 -1
  77. package/dist/matterbridgeEndpoint.js.map +0 -1
  78. package/dist/matterbridgePlatform.d.ts +0 -145
  79. package/dist/matterbridgePlatform.d.ts.map +0 -1
  80. package/dist/matterbridgePlatform.js.map +0 -1
  81. package/dist/matterbridgeTypes.d.ts +0 -172
  82. package/dist/matterbridgeTypes.d.ts.map +0 -1
  83. package/dist/matterbridgeTypes.js.map +0 -1
  84. package/dist/matterbridgeWebsocket.d.ts +0 -49
  85. package/dist/matterbridgeWebsocket.d.ts.map +0 -1
  86. package/dist/matterbridgeWebsocket.js.map +0 -1
  87. package/dist/pluginManager.d.ts +0 -238
  88. package/dist/pluginManager.d.ts.map +0 -1
  89. package/dist/pluginManager.js.map +0 -1
  90. package/dist/storage/export.d.ts +0 -2
  91. package/dist/storage/export.d.ts.map +0 -1
  92. package/dist/storage/export.js.map +0 -1
  93. package/dist/utils/colorUtils.d.ts +0 -61
  94. package/dist/utils/colorUtils.d.ts.map +0 -1
  95. package/dist/utils/colorUtils.js.map +0 -1
  96. package/dist/utils/export.d.ts +0 -3
  97. package/dist/utils/export.d.ts.map +0 -1
  98. package/dist/utils/export.js.map +0 -1
  99. package/dist/utils/utils.d.ts +0 -221
  100. package/dist/utils/utils.d.ts.map +0 -1
  101. package/dist/utils/utils.js.map +0 -1
  102. package/frontend/build/static/css/main.b1a621ee.css.map +0 -1
  103. package/frontend/build/static/js/main.ecd94d17.js.map +0 -1
  104. /package/frontend/build/static/js/{main.ecd94d17.js.LICENSE.txt → main.688f9551.js.LICENSE.txt} +0 -0
@@ -1,26 +1,3 @@
1
- /**
2
- * This file contains the class Matterbridge.
3
- *
4
- * @file matterbridge.ts
5
- * @author Luca Liguori
6
- * @date 2023-12-29
7
- * @version 1.5.2
8
- *
9
- * Copyright 2023, 2024, 2025 Luca Liguori.
10
- *
11
- * Licensed under the Apache License, Version 2.0 (the "License");
12
- * you may not use this file except in compliance with the License.
13
- * You may obtain a copy of the License at
14
- *
15
- * http://www.apache.org/licenses/LICENSE-2.0
16
- *
17
- * Unless required by applicable law or agreed to in writing, software
18
- * distributed under the License is distributed on an "AS IS" BASIS,
19
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20
- * See the License for the specific language governing permissions and
21
- * limitations under the License. *
22
- */
23
- // Node.js modules
24
1
  import { fileURLToPath } from 'url';
25
2
  import { promises as fs } from 'fs';
26
3
  import { exec, spawn } from 'child_process';
@@ -29,36 +6,27 @@ import EventEmitter from 'events';
29
6
  import os from 'os';
30
7
  import path from 'path';
31
8
  import { randomBytes } from 'crypto';
32
- // Package modules
33
9
  import https from 'https';
34
10
  import express from 'express';
35
11
  import WebSocket, { WebSocketServer } from 'ws';
36
- // NodeStorage and AnsiLogger modules
37
12
  import { NodeStorageManager } from 'node-persist-manager';
38
13
  import { AnsiLogger, UNDERLINE, UNDERLINEOFF, YELLOW, db, debugStringify, stringify, BRIGHT, RESET, er, nf, rs, wr, RED, GREEN, zb, CYAN, nt, idn, or, hk, BLUE } from 'node-ansi-logger';
39
- // Matterbridge
40
14
  import { MatterbridgeDevice } from './matterbridgeDevice.js';
41
15
  import { WS_ID_LOG, WS_ID_REFRESH_NEEDED, WS_ID_RESTART_NEEDED, wsMessageHandler } from './matterbridgeWebsocket.js';
42
16
  import { logInterfaces, wait, waiter, createZip, copyDirectory, getParameter, getIntParameter, hasParameter } from './utils/utils.js';
43
17
  import { PluginManager } from './pluginManager.js';
44
18
  import { DeviceManager } from './deviceManager.js';
45
19
  import { MatterbridgeEndpoint } from './matterbridgeEndpoint.js';
46
- // @matter
47
20
  import { DeviceTypeId, Logger, LogLevel as MatterLogLevel, LogFormat as MatterLogFormat, VendorId, StorageManager, EndpointServer, StorageService, Environment } from '@matter/main';
48
21
  import { BasicInformationCluster, BridgedDeviceBasicInformation, BridgedDeviceBasicInformationCluster, FixedLabelCluster, GeneralCommissioning, PowerSourceCluster, SwitchCluster, ThreadNetworkDiagnosticsCluster, UserLabelCluster, } from '@matter/main/clusters';
49
22
  import { getClusterNameById, ManualPairingCodeCodec, QrCodeSchema } from '@matter/main/types';
50
23
  import { StorageBackendDisk, StorageBackendJsonFile } from '@matter/nodejs';
51
- // @project-chip
52
24
  import { CommissioningController, CommissioningServer, MatterServer } from '@project-chip/matter.js';
53
25
  import { Aggregator, DeviceTypes, NodeStateInformation } from '@project-chip/matter.js/device';
54
26
  import { aggregator } from './matterbridgeDeviceTypes.js';
55
- // Default colors
56
27
  const plg = '\u001B[38;5;33m';
57
28
  const dev = '\u001B[38;5;79m';
58
29
  const typ = '\u001B[38;5;207m';
59
- /**
60
- * Represents the Matterbridge application.
61
- */
62
30
  export class Matterbridge extends EventEmitter {
63
31
  systemInformation = {
64
32
  interfaceName: '',
@@ -95,7 +63,7 @@ export class Matterbridge extends EventEmitter {
95
63
  edge: hasParameter('edge'),
96
64
  readOnly: hasParameter('readonly'),
97
65
  profile: getParameter('profile'),
98
- loggerLevel: "info" /* LogLevel.INFO */,
66
+ loggerLevel: "info",
99
67
  fileLogger: false,
100
68
  matterLoggerLevel: MatterLogLevel.INFO,
101
69
  matterFileLogger: false,
@@ -134,7 +102,6 @@ export class Matterbridge extends EventEmitter {
134
102
  nodeContext;
135
103
  matterStorageName = 'matterbridge' + (getParameter('profile') ? '.' + getParameter('profile') : '') + '.json';
136
104
  nodeStorageName = 'storage' + (getParameter('profile') ? '.' + getParameter('profile') : '');
137
- // Cleanup
138
105
  hasCleanupStarted = false;
139
106
  initialized = false;
140
107
  execRunningCount = 0;
@@ -146,18 +113,16 @@ export class Matterbridge extends EventEmitter {
146
113
  sigtermHandler;
147
114
  exceptionHandler;
148
115
  rejectionHandler;
149
- // Frontend
150
116
  expressApp;
151
117
  httpServer;
152
118
  httpsServer;
153
119
  webSocketServer;
154
- // Matter
155
- mdnsInterface; // matter server mdnsInterface: e.g. 'eth0' or 'wlan0' or 'WiFi'
156
- ipv4address; // matter commissioning server listeningAddressIpv4
157
- ipv6address; // matter commissioning server listeningAddressIpv6
158
- port = 5540; // first commissioning server port
159
- passcode; // first commissioning server passcode
160
- discriminator; // first commissioning server discriminator
120
+ mdnsInterface;
121
+ ipv4address;
122
+ ipv6address;
123
+ port = 5540;
124
+ passcode;
125
+ discriminator;
161
126
  storageManager;
162
127
  matterbridgeContext;
163
128
  mattercontrollerContext;
@@ -168,40 +133,19 @@ 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
- /**
178
- * Retrieves the list of Matterbridge devices.
179
- * @returns {MatterbridgeDevice[]} An array of MatterbridgeDevice objects.
180
- */
181
140
  getDevices() {
182
141
  return this.devices.array();
183
142
  }
184
- /**
185
- * Retrieves the list of registered plugins.
186
- * @returns {RegisteredPlugin[]} An array of RegisteredPlugin objects.
187
- */
188
143
  getPlugins() {
189
144
  return this.plugins.array();
190
145
  }
191
146
  matterbridgeMessageHandler;
192
- /** ***********************************************************************************************************************************/
193
- /** loadInstance() and cleanup() methods */
194
- /** ***********************************************************************************************************************************/
195
- /**
196
- * Loads an instance of the Matterbridge class.
197
- * If an instance already exists, return that instance.
198
- *
199
- * @param initialize - Whether to initialize the Matterbridge instance after loading.
200
- * @returns The loaded Matterbridge instance.
201
- */
202
147
  static async loadInstance(initialize = false) {
203
148
  if (!Matterbridge.instance) {
204
- // eslint-disable-next-line no-console
205
149
  if (hasParameter('debug'))
206
150
  console.log(GREEN + 'Creating a new instance of Matterbridge.', initialize ? 'Initializing...' : 'Not initializing...', rs);
207
151
  Matterbridge.instance = new Matterbridge();
@@ -210,11 +154,6 @@ export class Matterbridge extends EventEmitter {
210
154
  }
211
155
  return Matterbridge.instance;
212
156
  }
213
- /**
214
- * Call cleanup().
215
- * @deprecated This method is deprecated and is only used for jest tests.
216
- *
217
- */
218
157
  async destroyInstance() {
219
158
  await this.cleanup('destroying instance...', false);
220
159
  await waiter('destroying instance...', () => {
@@ -222,60 +161,39 @@ export class Matterbridge extends EventEmitter {
222
161
  }, false, 60000, 100, false);
223
162
  await wait(1000, 'Wait for the global node_modules and matterbridge version', false);
224
163
  }
225
- /**
226
- * Initializes the Matterbridge application.
227
- *
228
- * @remarks
229
- * This method performs the necessary setup and initialization steps for the Matterbridge application.
230
- * It displays the help information if the 'help' parameter is provided, sets up the logger, checks the
231
- * node version, registers signal handlers, initializes storage, and parses the command line.
232
- *
233
- * @returns A Promise that resolves when the initialization is complete.
234
- */
235
164
  async initialize() {
236
- // Set the restart mode
237
165
  if (hasParameter('service'))
238
166
  this.restartMode = 'service';
239
167
  if (hasParameter('docker'))
240
168
  this.restartMode = 'docker';
241
- // Set the matterbridge directory
242
169
  this.homeDirectory = getParameter('homedir') ?? os.homedir();
243
170
  this.matterbridgeDirectory = path.join(this.homeDirectory, '.matterbridge');
244
- // Create matterbridge logger
245
- this.log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: hasParameter('debug') ? "debug" /* LogLevel.DEBUG */ : "info" /* LogLevel.INFO */ });
246
- // Initialize nodeStorage and nodeContext
171
+ this.log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4, logLevel: hasParameter('debug') ? "debug" : "info" });
247
172
  try {
248
173
  this.log.debug(`Creating node storage manager: ${CYAN}${this.nodeStorageName}${db}`);
249
174
  this.nodeStorage = new NodeStorageManager({ dir: path.join(this.matterbridgeDirectory, this.nodeStorageName), writeQueue: false, expiredInterval: undefined, logging: false });
250
175
  this.log.debug('Creating node storage context for matterbridge');
251
176
  this.nodeContext = await this.nodeStorage.createStorage('matterbridge');
252
- // TODO: Remove this code when node-persist-manager is updated
253
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
254
177
  const keys = (await this.nodeStorage?.storage.keys());
255
178
  for (const key of keys) {
256
179
  this.log.debug(`Checking node storage manager key: ${CYAN}${key}${db}`);
257
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
258
180
  await this.nodeStorage?.storage.get(key);
259
181
  }
260
182
  const storages = await this.nodeStorage.getStorageNames();
261
183
  for (const storage of storages) {
262
184
  this.log.debug(`Checking storage: ${CYAN}${storage}${db}`);
263
185
  const nodeContext = await this.nodeStorage?.createStorage(storage);
264
- // TODO: Remove this code when node-persist-manager is updated
265
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
266
186
  const keys = (await nodeContext?.storage.keys());
267
187
  keys.forEach(async (key) => {
268
188
  this.log.debug(`Checking key: ${CYAN}${storage}:${key}${db}`);
269
189
  await nodeContext?.get(key);
270
190
  });
271
191
  }
272
- // Creating a backup of the node storage since it is not corrupted
273
192
  this.log.debug('Creating node storage backup...');
274
193
  await copyDirectory(path.join(this.matterbridgeDirectory, this.nodeStorageName), path.join(this.matterbridgeDirectory, this.nodeStorageName + '.backup'));
275
194
  this.log.debug('Created node storage backup');
276
195
  }
277
196
  catch (error) {
278
- // Restoring the backup of the node storage since it is corrupted
279
197
  this.log.error(`Error creating node storage manager and context: ${error instanceof Error ? error.message : error}`);
280
198
  if (hasParameter('norestore')) {
281
199
  this.log.fatal(`The matterbridge node storage is corrupted. Parameter -norestore found: exiting...`);
@@ -290,51 +208,45 @@ export class Matterbridge extends EventEmitter {
290
208
  this.log.fatal('Fatal error creating node storage manager and context for matterbridge');
291
209
  throw new Error('Fatal error creating node storage manager and context for matterbridge');
292
210
  }
293
- // Set the first port to use for the commissioning server (will be incremented in childbridge mode)
294
211
  this.port = getIntParameter('port') ?? (await this.nodeContext.get('matterport', 5540)) ?? 5540;
295
- // Set the first passcode to use for the commissioning server (will be incremented in childbridge mode)
296
212
  this.passcode = this.passcode ?? getIntParameter('passcode') ?? (await this.nodeContext.get('matterpasscode'));
297
- // Set the first discriminator to use for the commissioning server (will be incremented in childbridge mode)
298
213
  this.discriminator = this.discriminator ?? getIntParameter('discriminator') ?? (await this.nodeContext.get('matterdiscriminator'));
299
214
  this.log.debug(`Initializing commissioning server for Matterbridge... on port ${this.port} with passcode ${this.passcode} and discriminator ${this.discriminator}`);
300
- // Set matterbridge logger level (context: matterbridgeLogLevel)
301
215
  if (hasParameter('logger')) {
302
216
  const level = getParameter('logger');
303
217
  if (level === 'debug') {
304
- this.log.logLevel = "debug" /* LogLevel.DEBUG */;
218
+ this.log.logLevel = "debug";
305
219
  }
306
220
  else if (level === 'info') {
307
- this.log.logLevel = "info" /* LogLevel.INFO */;
221
+ this.log.logLevel = "info";
308
222
  }
309
223
  else if (level === 'notice') {
310
- this.log.logLevel = "notice" /* LogLevel.NOTICE */;
224
+ this.log.logLevel = "notice";
311
225
  }
312
226
  else if (level === 'warn') {
313
- this.log.logLevel = "warn" /* LogLevel.WARN */;
227
+ this.log.logLevel = "warn";
314
228
  }
315
229
  else if (level === 'error') {
316
- this.log.logLevel = "error" /* LogLevel.ERROR */;
230
+ this.log.logLevel = "error";
317
231
  }
318
232
  else if (level === 'fatal') {
319
- this.log.logLevel = "fatal" /* LogLevel.FATAL */;
233
+ this.log.logLevel = "fatal";
320
234
  }
321
235
  else {
322
236
  this.log.warn(`Invalid matterbridge logger level: ${level}. Using default level "info".`);
323
- this.log.logLevel = "info" /* LogLevel.INFO */;
237
+ this.log.logLevel = "info";
324
238
  }
325
239
  }
326
240
  else {
327
- this.log.logLevel = await this.nodeContext.get('matterbridgeLogLevel', "info" /* LogLevel.INFO */);
241
+ this.log.logLevel = await this.nodeContext.get('matterbridgeLogLevel', "info");
328
242
  }
329
243
  MatterbridgeDevice.logLevel = this.log.logLevel;
330
- // Create the file logger for matterbridge (context: matterbridgeFileLog)
331
244
  if (hasParameter('filelogger') || (await this.nodeContext.get('matterbridgeFileLog', false))) {
332
245
  AnsiLogger.setGlobalLogfile(path.join(this.matterbridgeDirectory, this.matterbrideLoggerFile), this.log.logLevel, true);
333
246
  this.matterbridgeInformation.fileLogger = true;
334
247
  }
335
248
  this.log.notice('Matterbridge is starting...');
336
249
  this.log.debug(`Matterbridge logLevel: ${this.log.logLevel} fileLoger: ${this.matterbridgeInformation.fileLogger}.`);
337
- // Set matter.js logger level, format and logger (context: matterLogLevel)
338
250
  if (hasParameter('matterlogger')) {
339
251
  const level = getParameter('matterlogger');
340
252
  if (level === 'debug') {
@@ -365,7 +277,6 @@ export class Matterbridge extends EventEmitter {
365
277
  }
366
278
  Logger.format = MatterLogFormat.ANSI;
367
279
  Logger.setLogger('default', this.createMatterLogger());
368
- // Create the file logger for matter.js (context: matterFileLog)
369
280
  if (hasParameter('matterfilelogger') || (await this.nodeContext.get('matterFileLog', false))) {
370
281
  this.matterbridgeInformation.matterFileLogger = true;
371
282
  Logger.addLogger('matterfilelogger', await this.createMatterFileLogger(path.join(this.matterbridgeDirectory, this.matterLoggerFile), true), {
@@ -374,7 +285,6 @@ export class Matterbridge extends EventEmitter {
374
285
  });
375
286
  }
376
287
  this.log.debug(`Matter logLevel: ${Logger.defaultLogLevel} fileLoger: ${this.matterbridgeInformation.matterFileLogger}.`);
377
- // Set the interface to use for the matter server mdnsInterface
378
288
  if (hasParameter('mdnsinterface')) {
379
289
  this.mdnsInterface = getParameter('mdnsinterface');
380
290
  }
@@ -383,7 +293,6 @@ export class Matterbridge extends EventEmitter {
383
293
  if (this.mdnsInterface === '')
384
294
  this.mdnsInterface = undefined;
385
295
  }
386
- // Set the listeningAddressIpv4 for the matter commissioning server
387
296
  if (hasParameter('ipv4address')) {
388
297
  this.ipv4address = getParameter('ipv4address');
389
298
  }
@@ -392,7 +301,6 @@ export class Matterbridge extends EventEmitter {
392
301
  if (this.ipv4address === '')
393
302
  this.ipv4address = undefined;
394
303
  }
395
- // Set the listeningAddressIpv6 for the matter commissioning server
396
304
  if (hasParameter('ipv6address')) {
397
305
  this.ipv6address = getParameter('ipv6address');
398
306
  }
@@ -401,23 +309,17 @@ export class Matterbridge extends EventEmitter {
401
309
  if (this.ipv6address === '')
402
310
  this.ipv6address = undefined;
403
311
  }
404
- // Initialize PluginManager
405
312
  this.plugins = new PluginManager(this);
406
313
  await this.plugins.loadFromStorage();
407
- // Initialize DeviceManager
408
314
  this.devices = new DeviceManager(this, this.nodeContext);
409
- // Get the plugins from node storage and create the plugins node storage contexts
410
315
  for (const plugin of this.plugins) {
411
316
  const packageJson = await this.plugins.parse(plugin);
412
317
  if (packageJson === null && !hasParameter('add')) {
413
- // Try to reinstall the plugin from npm (for Docker pull and external plugins)
414
- // We don't do this when the add parameter is set because we shut down the process after adding the plugin
415
318
  this.log.info(`Error parsing plugin ${plg}${plugin.name}${nf}. Trying to reinstall it from npm.`);
416
319
  try {
417
320
  await this.spawnCommand('npm', ['install', '-g', plugin.name, '--omit=dev', '--verbose']);
418
321
  this.log.info(`Plugin ${plg}${plugin.name}${nf} reinstalled.`);
419
322
  plugin.error = false;
420
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
421
323
  }
422
324
  catch (error) {
423
325
  plugin.error = true;
@@ -434,7 +336,6 @@ export class Matterbridge extends EventEmitter {
434
336
  await plugin.nodeContext.set('description', plugin.description);
435
337
  await plugin.nodeContext.set('author', plugin.author);
436
338
  }
437
- // Log system info and create .matterbridge directory
438
339
  await this.logNodeAndSystemInfo();
439
340
  this.log.notice(`Matterbridge version ${this.matterbridgeVersion} ` +
440
341
  `${hasParameter('bridge') || (!hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'bridge') ? 'mode bridge ' : ''}` +
@@ -442,7 +343,6 @@ export class Matterbridge extends EventEmitter {
442
343
  `${hasParameter('controller') ? 'mode controller ' : ''}` +
443
344
  `${this.restartMode !== '' ? 'restart mode ' + this.restartMode + ' ' : ''}` +
444
345
  `running on ${this.systemInformation.osType} (v.${this.systemInformation.osRelease}) platform ${this.systemInformation.osPlatform} arch ${this.systemInformation.osArch}`);
445
- // Check node version and throw error
446
346
  const minNodeVersion = 18;
447
347
  const nodeVersion = process.versions.node;
448
348
  const versionMajor = parseInt(nodeVersion.split('.')[0]);
@@ -450,17 +350,10 @@ export class Matterbridge extends EventEmitter {
450
350
  this.log.error(`Node version ${versionMajor} is not supported. Please upgrade to ${minNodeVersion} or above.`);
451
351
  throw new Error(`Node version ${versionMajor} is not supported. Please upgrade to ${minNodeVersion} or above.`);
452
352
  }
453
- // Register process handlers
454
353
  this.registerProcessHandlers();
455
- // Parse command line
456
354
  await this.parseCommandLine();
457
355
  this.initialized = true;
458
356
  }
459
- /**
460
- * Parses the command line arguments and performs the corresponding actions.
461
- * @private
462
- * @returns {Promise<void>} A promise that resolves when the command line arguments have been processed, or the process exits.
463
- */
464
357
  async parseCommandLine() {
465
358
  if (hasParameter('help')) {
466
359
  this.log.info(`\nUsage: matterbridge [options]\n
@@ -568,7 +461,6 @@ export class Matterbridge extends EventEmitter {
568
461
  }
569
462
  if (hasParameter('factoryreset')) {
570
463
  try {
571
- // Delete old matter storage file
572
464
  const file = path.join(this.matterbridgeDirectory, 'matterbridge' + (getParameter('profile') ? '.' + getParameter('profile') : '') + '.json');
573
465
  this.log.info(`Unlinking old matter storage file: ${file}`);
574
466
  await fs.unlink(file);
@@ -579,7 +471,6 @@ export class Matterbridge extends EventEmitter {
579
471
  }
580
472
  }
581
473
  try {
582
- // Delete matter node storage directory with its subdirectories
583
474
  const dir = path.join(this.matterbridgeDirectory, 'matterstorage' + (getParameter('profile') ? '.' + getParameter('profile') : ''));
584
475
  this.log.info(`Removing matter node storage directory: ${dir}`);
585
476
  await fs.rm(dir, { recursive: true });
@@ -590,7 +481,6 @@ export class Matterbridge extends EventEmitter {
590
481
  }
591
482
  }
592
483
  try {
593
- // Delete node storage directory with its subdirectories
594
484
  const dir = path.join(this.matterbridgeDirectory, 'storage' + (getParameter('profile') ? '.' + getParameter('profile') : ''));
595
485
  this.log.info(`Removing storage directory: ${dir}`);
596
486
  await fs.rm(dir, { recursive: true });
@@ -608,7 +498,6 @@ export class Matterbridge extends EventEmitter {
608
498
  this.emit('shutdown');
609
499
  return;
610
500
  }
611
- // Start the matter storage and create the matterbridge context
612
501
  try {
613
502
  await this.startMatterStorage('json', path.join(this.matterbridgeDirectory, this.matterStorageName));
614
503
  }
@@ -616,7 +505,6 @@ export class Matterbridge extends EventEmitter {
616
505
  this.log.fatal(`Fatal error creating matter storage: ${error instanceof Error ? error.message : error}`);
617
506
  throw new Error(`Fatal error creating matter storage: ${error instanceof Error ? error.message : error}`);
618
507
  }
619
- // Clear the matterbridge context if the reset parameter is set
620
508
  if (!this.edge && hasParameter('reset') && getParameter('reset') === undefined) {
621
509
  this.log.info('Resetting Matterbridge commissioning information...');
622
510
  await this.matterbridgeContext?.clearAll();
@@ -625,7 +513,6 @@ export class Matterbridge extends EventEmitter {
625
513
  this.emit('shutdown');
626
514
  return;
627
515
  }
628
- // Clear matterbridge plugin context if the reset parameter is set
629
516
  if (!this.edge && hasParameter('reset') && getParameter('reset') !== undefined) {
630
517
  this.log.debug(`Reset plugin ${getParameter('reset')}`);
631
518
  const plugin = this.plugins.get(getParameter('reset'));
@@ -645,34 +532,28 @@ export class Matterbridge extends EventEmitter {
645
532
  this.emit('shutdown');
646
533
  return;
647
534
  }
648
- // Initialize frontend
649
535
  if (getIntParameter('frontend') !== 0 || getIntParameter('frontend') === undefined)
650
536
  await this.initializeFrontend(getIntParameter('frontend'));
651
- // Check each 60 minutes the latest versions
652
537
  this.checkUpdateInterval = setInterval(() => {
653
538
  this.getMatterbridgeLatestVersion();
654
539
  for (const plugin of this.plugins) {
655
540
  this.getPluginLatestVersion(plugin);
656
541
  }
657
542
  }, 60 * 60 * 1000);
658
- // Start the matterbridge in mode test
659
543
  if (hasParameter('test')) {
660
544
  this.bridgeMode = 'bridge';
661
545
  MatterbridgeDevice.bridgeMode = 'bridge';
662
546
  return;
663
547
  }
664
- // Start the matterbridge in mode controller
665
548
  if (hasParameter('controller')) {
666
549
  this.bridgeMode = 'controller';
667
550
  await this.startController();
668
551
  return;
669
552
  }
670
- // Check if the bridge mode is set and start matterbridge in bridge mode if not set
671
553
  if (!hasParameter('bridge') && !hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === '') {
672
554
  this.log.info('Setting default matterbridge start mode to bridge');
673
555
  await this.nodeContext?.set('bridgeMode', 'bridge');
674
556
  }
675
- // Start matterbridge in bridge mode
676
557
  if (hasParameter('bridge') || (!hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'bridge')) {
677
558
  this.bridgeMode = 'bridge';
678
559
  MatterbridgeDevice.bridgeMode = 'bridge';
@@ -681,7 +562,6 @@ export class Matterbridge extends EventEmitter {
681
562
  await this.startBridge();
682
563
  return;
683
564
  }
684
- // Start matterbridge in childbridge mode
685
565
  if (hasParameter('childbridge') || (!hasParameter('bridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'childbridge')) {
686
566
  this.bridgeMode = 'childbridge';
687
567
  MatterbridgeDevice.bridgeMode = 'childbridge';
@@ -691,28 +571,17 @@ export class Matterbridge extends EventEmitter {
691
571
  return;
692
572
  }
693
573
  }
694
- /**
695
- * Asynchronously loads and starts the registered plugins.
696
- *
697
- * This method is responsible for initializing and staarting all enabled plugins.
698
- * It ensures that each plugin is properly loaded and started before the ridge starts.
699
- *
700
- * @returns {Promise<void>} A promise that resolves when all plugins have been loaded and started.
701
- */
702
574
  async startPlugins() {
703
- // Check, load and start the plugins
704
575
  for (const plugin of this.plugins) {
705
576
  plugin.configJson = await this.plugins.loadConfig(plugin);
706
577
  plugin.schemaJson = await this.plugins.loadSchema(plugin);
707
- // Check if the plugin is available
708
578
  if (!(await this.plugins.resolve(plugin.path))) {
709
579
  this.log.error(`Plugin ${plg}${plugin.name}${er} not found or not validated. Disabling it.`);
710
580
  plugin.enabled = false;
711
581
  plugin.error = true;
712
582
  continue;
713
583
  }
714
- // Check if the plugin has a new version
715
- this.getPluginLatestVersion(plugin); // No await do it asyncronously
584
+ this.getPluginLatestVersion(plugin);
716
585
  if (!plugin.enabled) {
717
586
  this.log.info(`Plugin ${plg}${plugin.name}${nf} not enabled`);
718
587
  continue;
@@ -727,26 +596,20 @@ export class Matterbridge extends EventEmitter {
727
596
  plugin.addedDevices = undefined;
728
597
  plugin.qrPairingCode = undefined;
729
598
  plugin.manualPairingCode = undefined;
730
- this.plugins.load(plugin, true, 'Matterbridge is starting'); // No await do it asyncronously
599
+ this.plugins.load(plugin, true, 'Matterbridge is starting');
731
600
  }
732
601
  this.wssSendRefreshRequired();
733
602
  }
734
- /**
735
- * Registers the process handlers for uncaughtException, unhandledRejection, SIGINT and SIGTERM.
736
- * When either of these signals are received, the cleanup method is called with an appropriate message.
737
- */
738
603
  registerProcessHandlers() {
739
604
  this.log.debug(`Registering uncaughtException and unhandledRejection handlers...`);
740
605
  process.removeAllListeners('uncaughtException');
741
606
  process.removeAllListeners('unhandledRejection');
742
607
  this.exceptionHandler = async (error) => {
743
608
  this.log.fatal('Unhandled Exception detected at:', error.stack || error, rs);
744
- // await this.cleanup('Unhandled Exception detected, cleaning up...');
745
609
  };
746
610
  process.on('uncaughtException', this.exceptionHandler);
747
611
  this.rejectionHandler = async (reason, promise) => {
748
612
  this.log.fatal('Unhandled Rejection detected at:', promise, 'reason:', reason instanceof Error ? reason.stack : reason, rs);
749
- // await this.cleanup('Unhandled Rejection detected, cleaning up...');
750
613
  };
751
614
  process.on('unhandledRejection', this.rejectionHandler);
752
615
  this.log.debug(`Registering SIGINT and SIGTERM signal handlers...`);
@@ -759,9 +622,6 @@ export class Matterbridge extends EventEmitter {
759
622
  };
760
623
  process.on('SIGTERM', this.sigtermHandler);
761
624
  }
762
- /**
763
- * Deregisters the process uncaughtException, unhandledRejection, SIGINT and SIGTERM signal handlers.
764
- */
765
625
  deregisterProcesslHandlers() {
766
626
  this.log.debug(`Deregistering uncaughtException and unhandledRejection handlers...`);
767
627
  if (this.exceptionHandler)
@@ -778,11 +638,7 @@ export class Matterbridge extends EventEmitter {
778
638
  process.off('SIGTERM', this.sigtermHandler);
779
639
  this.sigtermHandler = undefined;
780
640
  }
781
- /**
782
- * Logs the node and system information.
783
- */
784
641
  async logNodeAndSystemInfo() {
785
- // IP address information
786
642
  const networkInterfaces = os.networkInterfaces();
787
643
  this.systemInformation.ipv4Address = '';
788
644
  this.systemInformation.ipv6Address = '';
@@ -802,7 +658,7 @@ export class Matterbridge extends EventEmitter {
802
658
  this.systemInformation.macAddress = detail.mac;
803
659
  }
804
660
  }
805
- if (this.systemInformation.ipv4Address !== '' /* && this.systemInformation.ipv6Address !== ''*/) {
661
+ if (this.systemInformation.ipv4Address !== '') {
806
662
  this.log.debug(`Using interface: '${this.systemInformation.interfaceName}'`);
807
663
  this.log.debug(`- with MAC address: '${this.systemInformation.macAddress}'`);
808
664
  this.log.debug(`- with IPv4 address: '${this.systemInformation.ipv4Address}'`);
@@ -810,22 +666,19 @@ export class Matterbridge extends EventEmitter {
810
666
  break;
811
667
  }
812
668
  }
813
- // Node information
814
669
  this.systemInformation.nodeVersion = process.versions.node;
815
670
  const versionMajor = parseInt(this.systemInformation.nodeVersion.split('.')[0]);
816
671
  const versionMinor = parseInt(this.systemInformation.nodeVersion.split('.')[1]);
817
672
  const versionPatch = parseInt(this.systemInformation.nodeVersion.split('.')[2]);
818
- // Host system information
819
673
  this.systemInformation.hostname = os.hostname();
820
674
  this.systemInformation.user = os.userInfo().username;
821
- this.systemInformation.osType = os.type(); // "Windows_NT", "Darwin", etc.
822
- this.systemInformation.osRelease = os.release(); // Kernel version
823
- this.systemInformation.osPlatform = os.platform(); // "win32", "linux", "darwin", etc.
824
- this.systemInformation.osArch = os.arch(); // "x64", "arm", etc.
825
- this.systemInformation.totalMemory = (os.totalmem() / 1024 / 1024 / 1024).toFixed(2) + ' GB'; // Convert to GB
826
- this.systemInformation.freeMemory = (os.freemem() / 1024 / 1024 / 1024).toFixed(2) + ' GB'; // Convert to GB
827
- this.systemInformation.systemUptime = (os.uptime() / 60 / 60).toFixed(2) + ' hours'; // Convert to hours
828
- // Log the system information
675
+ this.systemInformation.osType = os.type();
676
+ this.systemInformation.osRelease = os.release();
677
+ this.systemInformation.osPlatform = os.platform();
678
+ this.systemInformation.osArch = os.arch();
679
+ this.systemInformation.totalMemory = (os.totalmem() / 1024 / 1024 / 1024).toFixed(2) + ' GB';
680
+ this.systemInformation.freeMemory = (os.freemem() / 1024 / 1024 / 1024).toFixed(2) + ' GB';
681
+ this.systemInformation.systemUptime = (os.uptime() / 60 / 60).toFixed(2) + ' hours';
829
682
  this.log.debug('Host System Information:');
830
683
  this.log.debug(`- Hostname: ${this.systemInformation.hostname}`);
831
684
  this.log.debug(`- User: ${this.systemInformation.user}`);
@@ -841,19 +694,15 @@ export class Matterbridge extends EventEmitter {
841
694
  this.log.debug(`- Total Memory: ${this.systemInformation.totalMemory}`);
842
695
  this.log.debug(`- Free Memory: ${this.systemInformation.freeMemory}`);
843
696
  this.log.debug(`- System Uptime: ${this.systemInformation.systemUptime}`);
844
- // Home directory
845
697
  this.homeDirectory = getParameter('homedir') ?? os.homedir();
846
698
  this.matterbridgeInformation.homeDirectory = this.homeDirectory;
847
699
  this.log.debug(`Home Directory: ${this.homeDirectory}`);
848
- // Package root directory
849
700
  const currentFileDirectory = path.dirname(fileURLToPath(import.meta.url));
850
701
  this.rootDirectory = path.resolve(currentFileDirectory, '../');
851
702
  this.matterbridgeInformation.rootDirectory = this.rootDirectory;
852
703
  this.log.debug(`Root Directory: ${this.rootDirectory}`);
853
- // Global node_modules directory
854
704
  if (this.nodeContext)
855
705
  this.globalModulesDirectory = await this.nodeContext.get('globalModulesDirectory', '');
856
- // First run of Matterbridge so the node storage is empty
857
706
  if (this.globalModulesDirectory === '') {
858
707
  try {
859
708
  this.globalModulesDirectory = await this.getGlobalNodeModules();
@@ -877,7 +726,6 @@ export class Matterbridge extends EventEmitter {
877
726
  this.log.error(`Error getting global node_modules directory: ${error}`);
878
727
  });
879
728
  }
880
- // Create the data directory .matterbridge in the home directory
881
729
  this.matterbridgeDirectory = path.join(this.homeDirectory, '.matterbridge');
882
730
  this.matterbridgeInformation.matterbridgeDirectory = this.matterbridgeDirectory;
883
731
  try {
@@ -901,7 +749,6 @@ export class Matterbridge extends EventEmitter {
901
749
  }
902
750
  }
903
751
  this.log.debug(`Matterbridge Directory: ${this.matterbridgeDirectory}`);
904
- // Create the plugin directory Matterbridge in the home directory
905
752
  this.matterbridgePluginDirectory = path.join(this.homeDirectory, 'Matterbridge');
906
753
  this.matterbridgeInformation.matterbridgePluginDirectory = this.matterbridgePluginDirectory;
907
754
  try {
@@ -925,28 +772,19 @@ export class Matterbridge extends EventEmitter {
925
772
  }
926
773
  }
927
774
  this.log.debug(`Matterbridge Plugin Directory: ${this.matterbridgePluginDirectory}`);
928
- // Matterbridge version
929
775
  const packageJson = JSON.parse(await fs.readFile(path.join(this.rootDirectory, 'package.json'), 'utf-8'));
930
776
  this.matterbridgeVersion = packageJson.version;
931
777
  this.matterbridgeInformation.matterbridgeVersion = this.matterbridgeVersion;
932
778
  this.log.debug(`Matterbridge Version: ${this.matterbridgeVersion}`);
933
- // Matterbridge latest version
934
779
  if (this.nodeContext)
935
780
  this.matterbridgeLatestVersion = await this.nodeContext.get('matterbridgeLatestVersion', '');
936
781
  this.log.debug(`Matterbridge Latest Version: ${this.matterbridgeLatestVersion}`);
937
782
  this.getMatterbridgeLatestVersion();
938
- // Current working directory
939
783
  const currentDir = process.cwd();
940
784
  this.log.debug(`Current Working Directory: ${currentDir}`);
941
- // Command line arguments (excluding 'node' and the script name)
942
785
  const cmdArgs = process.argv.slice(2).join(' ');
943
786
  this.log.debug(`Command Line Arguments: ${cmdArgs}`);
944
787
  }
945
- /**
946
- * Retrieves the latest version of a package from the npm registry.
947
- * @param packageName - The name of the package.
948
- * @returns A Promise that resolves to the latest version of the package.
949
- */
950
788
  async getLatestVersion(packageName) {
951
789
  return new Promise((resolve, reject) => {
952
790
  this.execRunningCount++;
@@ -961,10 +799,6 @@ export class Matterbridge extends EventEmitter {
961
799
  });
962
800
  });
963
801
  }
964
- /**
965
- * Retrieves the path to the global Node.js modules directory.
966
- * @returns A promise that resolves to the path of the global Node.js modules directory.
967
- */
968
802
  async getGlobalNodeModules() {
969
803
  return new Promise((resolve, reject) => {
970
804
  this.execRunningCount++;
@@ -979,11 +813,6 @@ export class Matterbridge extends EventEmitter {
979
813
  });
980
814
  });
981
815
  }
982
- /**
983
- * Retrieves the latest version of Matterbridge and performs necessary actions based on the version comparison.
984
- * @private
985
- * @returns {Promise<void>} A promise that resolves when the latest version is retrieved and actions are performed.
986
- */
987
816
  async getMatterbridgeLatestVersion() {
988
817
  this.getLatestVersion('matterbridge')
989
818
  .then(async (matterbridgeLatestVersion) => {
@@ -1000,19 +829,8 @@ export class Matterbridge extends EventEmitter {
1000
829
  })
1001
830
  .catch((error) => {
1002
831
  this.log.error(`Error getting Matterbridge latest version: ${error.message}`);
1003
- // error.stack && this.log.debug(error.stack);
1004
832
  });
1005
833
  }
1006
- /**
1007
- * Retrieves the latest version of a plugin and updates the plugin's latestVersion property.
1008
- * If the plugin's version is different from the latest version, logs a warning message.
1009
- * If the plugin's version is the same as the latest version, logs an info message.
1010
- * If there is an error retrieving the latest version, logs an error message.
1011
- *
1012
- * @private
1013
- * @param {RegisteredPlugin} plugin - The plugin for which to retrieve the latest version.
1014
- * @returns {Promise<void>} A promise that resolves when the latest version is retrieved and actions are performed.
1015
- */
1016
834
  async getPluginLatestVersion(plugin) {
1017
835
  this.getLatestVersion(plugin.name)
1018
836
  .then(async (latestVersion) => {
@@ -1024,54 +842,40 @@ export class Matterbridge extends EventEmitter {
1024
842
  })
1025
843
  .catch((error) => {
1026
844
  this.log.error(`Error getting ${plg}${plugin.name}${er} latest version: ${error.message}`);
1027
- // error.stack && this.log.debug(error.stack);
1028
845
  });
1029
846
  }
1030
- /**
1031
- * Creates a MatterLogger function to show the matter.js log messages in AnsiLogger (for the frontend).
1032
- *
1033
- * @returns {Function} The MatterLogger function.
1034
- */
1035
847
  createMatterLogger() {
1036
- const matterLogger = new AnsiLogger({ logName: 'Matter', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: "debug" /* LogLevel.DEBUG */ });
848
+ const matterLogger = new AnsiLogger({ logName: 'Matter', logTimestampFormat: 4, logLevel: "debug" });
1037
849
  return (_level, formattedLog) => {
1038
850
  const logger = formattedLog.slice(44, 44 + 20).trim();
1039
851
  const message = formattedLog.slice(65);
1040
852
  matterLogger.logName = logger;
1041
853
  switch (_level) {
1042
854
  case MatterLogLevel.DEBUG:
1043
- matterLogger.log("debug" /* LogLevel.DEBUG */, message);
855
+ matterLogger.log("debug", message);
1044
856
  break;
1045
857
  case MatterLogLevel.INFO:
1046
- matterLogger.log("info" /* LogLevel.INFO */, message);
858
+ matterLogger.log("info", message);
1047
859
  break;
1048
860
  case MatterLogLevel.NOTICE:
1049
- matterLogger.log("notice" /* LogLevel.NOTICE */, message);
861
+ matterLogger.log("notice", message);
1050
862
  break;
1051
863
  case MatterLogLevel.WARN:
1052
- matterLogger.log("warn" /* LogLevel.WARN */, message);
864
+ matterLogger.log("warn", message);
1053
865
  break;
1054
866
  case MatterLogLevel.ERROR:
1055
- matterLogger.log("error" /* LogLevel.ERROR */, message);
867
+ matterLogger.log("error", message);
1056
868
  break;
1057
869
  case MatterLogLevel.FATAL:
1058
- matterLogger.log("fatal" /* LogLevel.FATAL */, message);
870
+ matterLogger.log("fatal", message);
1059
871
  break;
1060
872
  default:
1061
- matterLogger.log("debug" /* LogLevel.DEBUG */, message);
873
+ matterLogger.log("debug", message);
1062
874
  break;
1063
875
  }
1064
876
  };
1065
877
  }
1066
- /**
1067
- * Creates a Matter File Logger.
1068
- *
1069
- * @param {string} filePath - The path to the log file.
1070
- * @param {boolean} [unlink=false] - Whether to unlink the log file before creating a new one.
1071
- * @returns {Function} - A function that logs formatted messages to the log file.
1072
- */
1073
878
  async createMatterFileLogger(filePath, unlink = false) {
1074
- // 2024-08-21 08:55:19.488 DEBUG InteractionMessenger Sending DataReport chunk with 28 attributes and 0 events: 1004 bytes
1075
879
  let fileSize = 0;
1076
880
  if (unlink) {
1077
881
  try {
@@ -1120,30 +924,18 @@ export class Matterbridge extends EventEmitter {
1120
924
  }
1121
925
  };
1122
926
  }
1123
- /**
1124
- * Update matterbridge and cleanup.
1125
- */
1126
927
  async updateProcess() {
1127
928
  await this.cleanup('updating...', false);
1128
929
  }
1129
- /**
1130
- * Restarts the process by spawning a new process and exiting the current process.
1131
- */
1132
930
  async restartProcess() {
1133
931
  await this.cleanup('restarting...', true);
1134
932
  }
1135
- /**
1136
- * Shut down the process by exiting the current process.
1137
- */
1138
933
  async shutdownProcess() {
1139
934
  await this.cleanup('shutting down...', false);
1140
935
  }
1141
- /**
1142
- * Shut down the process and reset.
1143
- */
1144
936
  async unregisterAndShutdownProcess() {
1145
937
  this.log.info('Unregistering all devices and shutting down...');
1146
- for (const plugin of this.plugins /* .filter((plugin) => plugin.enabled && !plugin.error))*/) {
938
+ for (const plugin of this.plugins) {
1147
939
  if (this.edge)
1148
940
  await this.removeAllBridgedEndpoints(plugin.name);
1149
941
  else
@@ -1151,55 +943,37 @@ export class Matterbridge extends EventEmitter {
1151
943
  }
1152
944
  await this.cleanup('unregistered all devices and shutting down...', false);
1153
945
  }
1154
- /**
1155
- * Shut down the process and reset.
1156
- */
1157
946
  async shutdownProcessAndReset() {
1158
947
  await this.cleanup('shutting down with reset...', false);
1159
948
  }
1160
- /**
1161
- * Shut down the process and factory reset.
1162
- */
1163
949
  async shutdownProcessAndFactoryReset() {
1164
950
  await this.cleanup('shutting down with factory reset...', false);
1165
951
  }
1166
- /**
1167
- * Cleans up the Matterbridge instance.
1168
- * @param message - The cleanup message.
1169
- * @param restart - Indicates whether to restart the instance after cleanup. Default is `false`.
1170
- * @returns A promise that resolves when the cleanup is completed.
1171
- */
1172
952
  async cleanup(message, restart = false) {
1173
953
  if (this.initialized && !this.hasCleanupStarted) {
1174
954
  this.hasCleanupStarted = true;
1175
955
  this.log.info(message);
1176
- // Deregisters the process handlers
1177
956
  this.deregisterProcesslHandlers();
1178
- // Clear the start matter interval
1179
957
  if (this.startMatterInterval) {
1180
958
  clearInterval(this.startMatterInterval);
1181
959
  this.startMatterInterval = undefined;
1182
960
  this.log.debug('Start matter interval cleared');
1183
961
  }
1184
- // Clear the check update interval
1185
962
  if (this.checkUpdateInterval) {
1186
963
  clearInterval(this.checkUpdateInterval);
1187
964
  this.checkUpdateInterval = undefined;
1188
965
  this.log.debug('Check update interval cleared');
1189
966
  }
1190
- // Clear the configure timeout
1191
967
  if (this.configureTimeout) {
1192
968
  clearTimeout(this.configureTimeout);
1193
969
  this.configureTimeout = undefined;
1194
970
  this.log.debug('Matterbridge configure timeout cleared');
1195
971
  }
1196
- // Clear the reachability timeout
1197
972
  if (this.reachabilityTimeout) {
1198
973
  clearTimeout(this.reachabilityTimeout);
1199
974
  this.reachabilityTimeout = undefined;
1200
975
  this.log.debug('Matterbridge reachability timeout cleared');
1201
976
  }
1202
- // Calling the shutdown method of each plugin and clear the reachability timeout
1203
977
  for (const plugin of this.plugins) {
1204
978
  if (!plugin.enabled || plugin.error)
1205
979
  continue;
@@ -1210,7 +984,6 @@ export class Matterbridge extends EventEmitter {
1210
984
  this.log.debug(`Plugin ${plg}${plugin.name}${db} reachability timeout cleared`);
1211
985
  }
1212
986
  }
1213
- // Convert the matter storage to the new format
1214
987
  if (!hasParameter('nostorageconversion') && this.edge === false && this.matterbridgeContext && ['updating...', 'restarting...', 'shutting down...'].includes(message)) {
1215
988
  if (this.bridgeMode === 'bridge') {
1216
989
  await this.convertStorage(this.matterbridgeContext, 'Matterbridge');
@@ -1223,29 +996,24 @@ export class Matterbridge extends EventEmitter {
1223
996
  }
1224
997
  }
1225
998
  }
1226
- // Close the http server
1227
999
  if (this.httpServer) {
1228
1000
  this.httpServer.close();
1229
1001
  this.httpServer.removeAllListeners();
1230
1002
  this.httpServer = undefined;
1231
1003
  this.log.debug('Frontend http server closed successfully');
1232
1004
  }
1233
- // Close the https server
1234
1005
  if (this.httpsServer) {
1235
1006
  this.httpsServer.close();
1236
1007
  this.httpsServer.removeAllListeners();
1237
1008
  this.httpsServer = undefined;
1238
1009
  this.log.debug('Frontend https server closed successfully');
1239
1010
  }
1240
- // Remove listeners from the express app
1241
1011
  if (this.expressApp) {
1242
1012
  this.expressApp.removeAllListeners();
1243
1013
  this.expressApp = undefined;
1244
1014
  this.log.debug('Frontend app closed successfully');
1245
1015
  }
1246
- // Close the WebSocket server
1247
1016
  if (this.webSocketServer) {
1248
- // Close all active connections
1249
1017
  this.webSocketServer.clients.forEach((client) => {
1250
1018
  if (client.readyState === WebSocket.OPEN) {
1251
1019
  client.close();
@@ -1261,35 +1029,26 @@ export class Matterbridge extends EventEmitter {
1261
1029
  });
1262
1030
  this.webSocketServer = undefined;
1263
1031
  }
1264
- // Closing matter
1265
1032
  await this.stopMatterServer();
1266
- // Closing matter storage
1267
1033
  await this.stopMatterStorage();
1268
- // Remove the matterfilelogger
1269
1034
  try {
1270
1035
  Logger.removeLogger('matterfilelogger');
1271
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1272
1036
  }
1273
1037
  catch (error) {
1274
- // this.log.debug(`Error removing the matterfilelogger for file ${CYAN}${path.join(this.matterbridgeDirectory, this.matterLoggerFile)}${er}: ${error instanceof Error ? error.message : error}`);
1275
1038
  }
1276
- // Serialize registeredDevices
1277
1039
  if (this.nodeStorage && this.nodeContext) {
1278
1040
  this.log.info('Saving registered devices...');
1279
1041
  const serializedRegisteredDevices = [];
1280
1042
  this.devices.forEach(async (device) => {
1281
1043
  const serializedMatterbridgeDevice = device.serialize();
1282
- // this.log.info(`- ${serializedMatterbridgeDevice.deviceName}${rs}\n`, serializedMatterbridgeDevice);
1283
1044
  if (serializedMatterbridgeDevice)
1284
1045
  serializedRegisteredDevices.push(serializedMatterbridgeDevice);
1285
1046
  });
1286
1047
  await this.nodeContext.set('devices', serializedRegisteredDevices);
1287
1048
  this.log.info(`Saved registered devices (${serializedRegisteredDevices?.length})`);
1288
- // Clear nodeContext and nodeStorage (they just need 1000ms to write the data to disk)
1289
1049
  this.log.debug(`Closing node storage context for ${plg}Matterbridge${db}...`);
1290
1050
  await this.nodeContext.close();
1291
1051
  this.nodeContext = undefined;
1292
- // Clear nodeContext for each plugin (they just need 1000ms to write the data to disk)
1293
1052
  for (const plugin of this.plugins) {
1294
1053
  if (plugin.nodeContext) {
1295
1054
  this.log.debug(`Closing node storage context for plugin ${plg}${plugin.name}${db}...`);
@@ -1321,7 +1080,6 @@ export class Matterbridge extends EventEmitter {
1321
1080
  else {
1322
1081
  if (message === 'shutting down with reset...' || message === 'shutting down with factory reset...') {
1323
1082
  try {
1324
- // Delete old matter storage file
1325
1083
  const file = path.join(this.matterbridgeDirectory, 'matterbridge' + (getParameter('profile') ? '.' + getParameter('profile') : '') + '.json');
1326
1084
  this.log.info(`Unlinking old matter storage file: ${file}`);
1327
1085
  await fs.unlink(file);
@@ -1330,7 +1088,6 @@ export class Matterbridge extends EventEmitter {
1330
1088
  this.log.debug(`Error resetting old matter storage file: ${error}`);
1331
1089
  }
1332
1090
  try {
1333
- // Delete matter node storage directory with its subdirectories
1334
1091
  const dir = path.join(this.matterbridgeDirectory, 'matterstorage' + (getParameter('profile') ? '.' + getParameter('profile') : ''));
1335
1092
  this.log.info(`Removing matter node storage directory: ${dir}`);
1336
1093
  await fs.rm(dir, { recursive: true });
@@ -1342,7 +1099,6 @@ export class Matterbridge extends EventEmitter {
1342
1099
  }
1343
1100
  if (message === 'shutting down with factory reset...') {
1344
1101
  try {
1345
- // Delete node storage directory with its subdirectories
1346
1102
  this.log.info('Resetting Matterbridge storage...');
1347
1103
  await fs.rm(path.join(this.matterbridgeDirectory, this.nodeStorageName), { recursive: true });
1348
1104
  }
@@ -1359,33 +1115,19 @@ export class Matterbridge extends EventEmitter {
1359
1115
  this.initialized = false;
1360
1116
  }
1361
1117
  }
1362
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1363
1118
  async addBridgedEndpoint(pluginName, device) {
1364
- // Nothing to do here
1365
1119
  }
1366
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1367
1120
  async removeBridgedEndpoint(pluginName, device) {
1368
- // Nothing to do here
1369
1121
  }
1370
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1371
1122
  async removeAllBridgedEndpoints(pluginName) {
1372
- // Nothing to do here
1373
1123
  }
1374
- /**
1375
- * Adds a bridged device to the Matterbridge.
1376
- * @param pluginName - The name of the plugin.
1377
- * @param device - The bridged device to add.
1378
- * @returns {Promise<void>} - A promise that resolves when the device is added.
1379
- */
1380
1124
  async addBridgedDevice(pluginName, device) {
1381
1125
  this.log.debug(`Adding bridged device ${dev}${device.deviceName}${db} (${zb}${device.name}${db}) for plugin ${plg}${pluginName}${db}`);
1382
- // Check if the plugin is registered
1383
1126
  const plugin = this.plugins.get(pluginName);
1384
1127
  if (!plugin) {
1385
1128
  this.log.error(`Error adding bridged device ${dev}${device.deviceName}${er} (${zb}${device.name}${er}) plugin ${plg}${pluginName}${er} not found`);
1386
1129
  return;
1387
1130
  }
1388
- // Register and add the device to matterbridge aggregator in bridge mode
1389
1131
  if (this.bridgeMode === 'bridge') {
1390
1132
  if (!this.matterAggregator) {
1391
1133
  this.log.error(`Adding bridged device ${dev}${device.deviceName}${er} (${zb}${device.name}${er}) for plugin ${plg}${pluginName}${er} error: matterAggregator not found`);
@@ -1393,11 +1135,8 @@ export class Matterbridge extends EventEmitter {
1393
1135
  }
1394
1136
  this.matterAggregator.addBridgedDevice(device);
1395
1137
  }
1396
- // The first time create the commissioning server and the aggregator for DynamicPlatform
1397
- // Register and add the device in childbridge mode
1398
1138
  if (this.bridgeMode === 'childbridge') {
1399
1139
  if (plugin.type === 'AccessoryPlatform') {
1400
- // Check if the plugin is locked with the commissioning server
1401
1140
  if (!plugin.locked) {
1402
1141
  plugin.locked = true;
1403
1142
  plugin.storageContext = await this.importCommissioningServerContext(plugin.name, device);
@@ -1411,7 +1150,6 @@ export class Matterbridge extends EventEmitter {
1411
1150
  }
1412
1151
  }
1413
1152
  if (plugin.type === 'DynamicPlatform') {
1414
- // Check if the plugin is locked with the commissioning server and the aggregator
1415
1153
  if (!plugin.locked) {
1416
1154
  plugin.locked = true;
1417
1155
  this.log.debug(`Creating commissioning server context for ${plg}${plugin.name}${db}`);
@@ -1432,25 +1170,16 @@ export class Matterbridge extends EventEmitter {
1432
1170
  plugin.registeredDevices++;
1433
1171
  if (plugin.addedDevices !== undefined)
1434
1172
  plugin.addedDevices++;
1435
- // Add the device to the DeviceManager
1436
1173
  this.devices.set(device);
1437
1174
  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}`);
1438
1175
  }
1439
- /**
1440
- * Removes a bridged device from the Matterbridge.
1441
- * @param pluginName - The name of the plugin.
1442
- * @param device - The device to be removed.
1443
- * @returns A Promise that resolves when the device is successfully removed.
1444
- */
1445
1176
  async removeBridgedDevice(pluginName, device) {
1446
1177
  this.log.debug(`Removing bridged device ${dev}${device.deviceName}${db} (${zb}${device.name}${db}) for plugin ${plg}${pluginName}${db}`);
1447
- // Check if the plugin is registered
1448
1178
  const plugin = this.plugins.get(pluginName);
1449
1179
  if (!plugin) {
1450
1180
  this.log.error(`Error removing bridged device ${dev}${device.deviceName}${er} (${zb}${device.name}${er}) for plugin ${plg}${pluginName}${er}: plugin not found`);
1451
1181
  return;
1452
1182
  }
1453
- // Remove the device from matterbridge aggregator in bridge mode
1454
1183
  if (this.bridgeMode === 'bridge') {
1455
1184
  if (!this.matterAggregator) {
1456
1185
  this.log.error(`Error removing bridged device ${dev}${device.deviceName}${er} (${zb}${device.name}${er}) for plugin ${plg}${pluginName}${er}: matterAggregator not found`);
@@ -1460,8 +1189,6 @@ export class Matterbridge extends EventEmitter {
1460
1189
  device.setBridgedDeviceReachability(false);
1461
1190
  device.getClusterServerById(BridgedDeviceBasicInformation.Cluster.id)?.triggerReachableChangedEvent({ reachableNewValue: false });
1462
1191
  }
1463
- // device.getClusterServerById(BridgedDeviceBasicInformation.Cluster.id)?.triggerShutDownEvent({});
1464
- // device.getClusterServerById(BridgedDeviceBasicInformation.Cluster.id)?.triggerLeaveEvent({});
1465
1192
  this.matterAggregator?.removeBridgedDevice(device);
1466
1193
  this.log.info(`Removed bridged device(${plugin.registeredDevices}/${plugin.addedDevices}) ${dev}${device.deviceName}${nf} (${zb}${device.name}${nf}) for plugin ${plg}${pluginName}${nf}`);
1467
1194
  if (plugin.registeredDevices !== undefined)
@@ -1469,7 +1196,6 @@ export class Matterbridge extends EventEmitter {
1469
1196
  if (plugin.addedDevices !== undefined)
1470
1197
  plugin.addedDevices--;
1471
1198
  }
1472
- // Remove the device in childbridge mode
1473
1199
  if (this.bridgeMode === 'childbridge') {
1474
1200
  if (plugin.type === 'AccessoryPlatform') {
1475
1201
  if (!plugin.commissioningServer) {
@@ -1493,22 +1219,14 @@ export class Matterbridge extends EventEmitter {
1493
1219
  plugin.registeredDevices--;
1494
1220
  if (plugin.addedDevices !== undefined)
1495
1221
  plugin.addedDevices--;
1496
- // Remove the commissioning server
1497
1222
  if (plugin.registeredDevices === 0 && plugin.addedDevices === 0 && plugin.commissioningServer) {
1498
1223
  this.matterServer?.removeCommissioningServer(plugin.commissioningServer);
1499
1224
  plugin.commissioningServer = undefined;
1500
1225
  this.log.info(`Removed commissioning server for plugin ${plg}${pluginName}${nf}`);
1501
1226
  }
1502
1227
  }
1503
- // Remove the device from the DeviceManager
1504
1228
  this.devices.remove(device);
1505
1229
  }
1506
- /**
1507
- * Removes all bridged devices associated with a specific plugin.
1508
- *
1509
- * @param pluginName - The name of the plugin.
1510
- * @returns A promise that resolves when all devices have been removed.
1511
- */
1512
1230
  async removeAllBridgedDevices(pluginName) {
1513
1231
  this.log.debug(`Removing all bridged devices for plugin ${plg}${pluginName}${db}`);
1514
1232
  this.devices.forEach(async (device) => {
@@ -1517,13 +1235,7 @@ export class Matterbridge extends EventEmitter {
1517
1235
  }
1518
1236
  });
1519
1237
  }
1520
- /**
1521
- * Starts the Matterbridge in bridge mode.
1522
- * @private
1523
- * @returns {Promise<void>} A promise that resolves when the Matterbridge is started.
1524
- */
1525
1238
  async startBridge() {
1526
- // Plugins are configured by a timer when matter server is started and plugin.configured is set to true
1527
1239
  if (!this.storageManager)
1528
1240
  throw new Error('No storage manager initialized');
1529
1241
  if (!this.matterbridgeContext)
@@ -1542,7 +1254,6 @@ export class Matterbridge extends EventEmitter {
1542
1254
  let failCount = 0;
1543
1255
  this.startMatterInterval = setInterval(async () => {
1544
1256
  for (const plugin of this.plugins) {
1545
- // new code to not start the bridge if one plugin is in error cause the controllers will delete the devices loosing all the configuration
1546
1257
  if (!plugin.enabled)
1547
1258
  continue;
1548
1259
  if (plugin.error) {
@@ -1567,18 +1278,15 @@ export class Matterbridge extends EventEmitter {
1567
1278
  clearInterval(this.startMatterInterval);
1568
1279
  this.startMatterInterval = undefined;
1569
1280
  this.log.debug('Cleared startMatterInterval interval for Matterbridge');
1570
- // Start the Matter server
1571
1281
  await this.startMatterServer();
1572
1282
  this.log.notice('Matter server started');
1573
- // Show the QR code for commissioning or log the already commissioned message
1574
1283
  await this.showCommissioningQRCode(this.commissioningServer, this.matterbridgeContext, this.nodeContext, 'Matterbridge');
1575
- // Configure the plugins
1576
1284
  this.configureTimeout = setTimeout(async () => {
1577
1285
  for (const plugin of this.plugins) {
1578
1286
  if (!plugin.enabled || !plugin.loaded || !plugin.started || plugin.error)
1579
1287
  continue;
1580
1288
  try {
1581
- await this.plugins.configure(plugin); // TODO No await do it in parallel
1289
+ await this.plugins.configure(plugin);
1582
1290
  }
1583
1291
  catch (error) {
1584
1292
  plugin.error = true;
@@ -1587,7 +1295,6 @@ export class Matterbridge extends EventEmitter {
1587
1295
  }
1588
1296
  this.wssSendRefreshRequired();
1589
1297
  }, 30 * 1000);
1590
- // Setting reachability to true
1591
1298
  this.reachabilityTimeout = setTimeout(() => {
1592
1299
  this.log.info(`Setting reachability to true for ${plg}Matterbridge${db}`);
1593
1300
  if (this.commissioningServer)
@@ -1597,14 +1304,7 @@ export class Matterbridge extends EventEmitter {
1597
1304
  }, 60 * 1000);
1598
1305
  }, 1000);
1599
1306
  }
1600
- /**
1601
- * Starts the Matterbridge in childbridge mode.
1602
- * @private
1603
- * @returns {Promise<void>} A promise that resolves when the Matterbridge is started.
1604
- */
1605
1307
  async startChildbridge() {
1606
- // Matterbridge.addBridgedDevice creates the commissionig servers and add the devices to the the commissioning server or to the aggregator
1607
- // Plugins are configured by a timer when matter server is started and plugin.configured is set to true
1608
1308
  if (!this.storageManager)
1609
1309
  throw new Error('No storage manager initialized');
1610
1310
  this.matterServer = await this.createMatterServer(this.storageManager);
@@ -1614,7 +1314,6 @@ export class Matterbridge extends EventEmitter {
1614
1314
  this.startMatterInterval = setInterval(async () => {
1615
1315
  let allStarted = true;
1616
1316
  for (const plugin of this.plugins) {
1617
- // Prevents to start the bridge if one plugin is in error cause the controllers will delete the devices loosing all the configuration
1618
1317
  if (!plugin.enabled)
1619
1318
  continue;
1620
1319
  if (plugin.error) {
@@ -1642,16 +1341,14 @@ export class Matterbridge extends EventEmitter {
1642
1341
  clearInterval(this.startMatterInterval);
1643
1342
  this.startMatterInterval = undefined;
1644
1343
  this.log.debug('Cleared startMatterInterval interval in childbridge mode');
1645
- // Start the Matter server
1646
1344
  await this.startMatterServer();
1647
1345
  this.log.notice('Matter server started');
1648
- // Configure the plugins
1649
1346
  this.configureTimeout = setTimeout(async () => {
1650
1347
  for (const plugin of this.plugins) {
1651
1348
  if (!plugin.enabled || !plugin.loaded || !plugin.started || plugin.error)
1652
1349
  continue;
1653
1350
  try {
1654
- await this.plugins.configure(plugin); // TODO No await do it in parallel
1351
+ await this.plugins.configure(plugin);
1655
1352
  }
1656
1353
  catch (error) {
1657
1354
  plugin.error = true;
@@ -1680,7 +1377,6 @@ export class Matterbridge extends EventEmitter {
1680
1377
  continue;
1681
1378
  }
1682
1379
  await this.showCommissioningQRCode(plugin.commissioningServer, plugin.storageContext, plugin.nodeContext, plugin.name);
1683
- // Setting reachability to true
1684
1380
  plugin.reachabilityTimeout = setTimeout(() => {
1685
1381
  this.log.info(`Setting reachability to true for ${plg}${plugin.name}${db}`);
1686
1382
  if (plugin.commissioningServer)
@@ -1693,11 +1389,6 @@ export class Matterbridge extends EventEmitter {
1693
1389
  }
1694
1390
  }, 1000);
1695
1391
  }
1696
- /**
1697
- * Starts the Matterbridge controller.
1698
- * @private
1699
- * @returns {Promise<void>} A promise that resolves when the Matterbridge is started.
1700
- */
1701
1392
  async startController() {
1702
1393
  if (!this.storageManager) {
1703
1394
  this.log.error('No storage manager initialized');
@@ -1760,7 +1451,7 @@ export class Matterbridge extends EventEmitter {
1760
1451
  const nodeId = await this.commissioningController.commissionNode(options);
1761
1452
  this.log.info(`Commissioning successfully done with nodeId: ${nodeId}`);
1762
1453
  this.log.info('ActiveSessionInformation:', this.commissioningController.getActiveSessionInformation());
1763
- } // (hasParameter('pairingcode'))
1454
+ }
1764
1455
  if (hasParameter('unpairall')) {
1765
1456
  this.log.info('***Commissioning controller unpairing all nodes...');
1766
1457
  const nodeIds = this.commissioningController.getCommissionedNodes();
@@ -1771,8 +1462,6 @@ export class Matterbridge extends EventEmitter {
1771
1462
  return;
1772
1463
  }
1773
1464
  if (hasParameter('discover')) {
1774
- // const discover = await this.commissioningController.discoverCommissionableDevices({ productId: 0x8000, deviceType: 0xfff1 });
1775
- // console.log(discover);
1776
1465
  }
1777
1466
  if (!this.commissioningController.isCommissioned()) {
1778
1467
  this.log.info('***Commissioning controller is not commissioned: use matterbridge -controller -pairingcode [pairingcode] to commission a device');
@@ -1813,12 +1502,10 @@ export class Matterbridge extends EventEmitter {
1813
1502
  },
1814
1503
  });
1815
1504
  node.logStructure();
1816
- // Get the interaction client
1817
1505
  this.log.info('Getting the interaction client');
1818
1506
  const interactionClient = await node.getInteractionClient();
1819
1507
  let cluster;
1820
1508
  let attributes;
1821
- // Log BasicInformationCluster
1822
1509
  cluster = BasicInformationCluster;
1823
1510
  attributes = await interactionClient.getMultipleAttributes({
1824
1511
  attributes: [{ clusterId: cluster.id }],
@@ -1828,7 +1515,6 @@ export class Matterbridge extends EventEmitter {
1828
1515
  attributes.forEach((attribute) => {
1829
1516
  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}`);
1830
1517
  });
1831
- // Log PowerSourceCluster
1832
1518
  cluster = PowerSourceCluster;
1833
1519
  attributes = await interactionClient.getMultipleAttributes({
1834
1520
  attributes: [{ clusterId: cluster.id }],
@@ -1838,7 +1524,6 @@ export class Matterbridge extends EventEmitter {
1838
1524
  attributes.forEach((attribute) => {
1839
1525
  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}`);
1840
1526
  });
1841
- // Log ThreadNetworkDiagnostics
1842
1527
  cluster = ThreadNetworkDiagnosticsCluster;
1843
1528
  attributes = await interactionClient.getMultipleAttributes({
1844
1529
  attributes: [{ clusterId: cluster.id }],
@@ -1848,7 +1533,6 @@ export class Matterbridge extends EventEmitter {
1848
1533
  attributes.forEach((attribute) => {
1849
1534
  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}`);
1850
1535
  });
1851
- // Log SwitchCluster
1852
1536
  cluster = SwitchCluster;
1853
1537
  attributes = await interactionClient.getMultipleAttributes({
1854
1538
  attributes: [{ clusterId: cluster.id }],
@@ -1869,15 +1553,6 @@ export class Matterbridge extends EventEmitter {
1869
1553
  this.log.info('Subscribed to all attributes and events');
1870
1554
  }
1871
1555
  }
1872
- /** ***********************************************************************************************************************************/
1873
- /** Matter.js methods */
1874
- /** ***********************************************************************************************************************************/
1875
- /**
1876
- * Starts the matter storage process based on the specified storage type and name.
1877
- * @param {string} storageType - The type of storage to start (e.g., 'disk', 'json').
1878
- * @param {string} storageName - The name of the storage file.
1879
- * @returns {Promise<void>} - A promise that resolves when the storage process is started.
1880
- */
1881
1556
  async startMatterStorage(storageType, storageName) {
1882
1557
  this.log.debug(`Starting matter ${storageType} storage ${CYAN}${storageName}${db}`);
1883
1558
  if (storageType === 'disk') {
@@ -1926,12 +1601,6 @@ export class Matterbridge extends EventEmitter {
1926
1601
  await this.matterbridgeContext.set('passcode', this.passcode);
1927
1602
  await this.matterbridgeContext.set('discriminator', this.discriminator);
1928
1603
  }
1929
- /**
1930
- * Convert the old API matter storage to the new API format.
1931
- * @param {StorageContext} context - The context of Matterbridge or of the plugin.
1932
- * @param {string} pluginName - The name of the plugin or Matterbridge.
1933
- * @returns {Promise<void>} - A promise that resolves when the storage process is started.
1934
- */
1935
1604
  async convertStorage(context, pluginName) {
1936
1605
  if (this.edge !== false)
1937
1606
  return;
@@ -1946,19 +1615,13 @@ export class Matterbridge extends EventEmitter {
1946
1615
  else {
1947
1616
  this.log.notice(`Converting matter node storage to Matterbridge edge for ${plg}${pluginName}${nt}...`);
1948
1617
  }
1949
- // Read FabricManager from the old storage and get FabricManager.fabrics and FabricManager.nextFabricIndex
1950
1618
  const fabricManagerContext = context.createContext('FabricManager');
1951
1619
  const fabrics = (await fabricManagerContext.get('fabrics', []));
1952
1620
  const nextFabricIndex = await fabricManagerContext.get('nextFabricIndex', 0);
1953
- // Read EventHandler from the old storage
1954
1621
  const eventHandlerContext = context.createContext('EventHandler');
1955
- // Read SessionManager from the old storage
1956
1622
  const sessionManagerContext = context.createContext('SessionManager');
1957
- // Read EndpointStructure from the old storage
1958
1623
  const endpointStructureContext = context.createContext('EndpointStructure');
1959
- // Read generalCommissioning from the old storage
1960
1624
  const generalCommissioningContext = context.createContext('Cluster-0-48');
1961
- // Read basicInformation from the old storage
1962
1625
  const basicInformationContext = context.createContext('Cluster-0-40');
1963
1626
  const fabricInfo = {};
1964
1627
  const fabricInfoArray = [];
@@ -2012,13 +1675,8 @@ export class Matterbridge extends EventEmitter {
2012
1675
  await nodeStorage.createContext('root').createContext('commissioning').set('fabrics', fabricInfo);
2013
1676
  await nodeStorage.createContext('root').createContext('operationalCredentials').set('commissionedFabrics', fabricInfoArray.length);
2014
1677
  await nodeStorage.createContext('root').createContext('operationalCredentials').set('fabrics', fabricInfoArray);
2015
- // operationalCredentials.nocs ==>> [{noc: fabric.operationalCert, icac: null, fabricIndex: fabric.fabricIndex }]
2016
1678
  await nodeStorage.createContext('root').createContext('operationalCredentials').set('nocs', nocArray);
2017
- // operationalCredentials.trustedRootCertificates ==>> ["{\"__object__\":\"Uint8Array\",\"__value__\":\"" + fabric.rootCert + "\"}"]
2018
1679
  await nodeStorage.createContext('root').createContext('operationalCredentials').set('trustedRootCertificates', trcArray);
2019
- // ACL updated, updating ACL manager { fabricIndex: 3, privilege: 5, authMode: 2, subjects: [ 18446744060825763897 ], targets: null }
2020
- // From fabric.rootNodeId if fabric.scopedClusterData.get(0x1f).get('acl') is empty
2021
- // [{"fabricIndex":3,"privilege":5,"authMode":2,"subjects":["{\"__object__\":\"BigInt\",\"__value__\":\"18446744060825763897\"}"],"targets":null}]
2022
1680
  await nodeStorage.createContext('root').createContext('accessControl').set('acl', aclArray);
2023
1681
  await nodeStorage
2024
1682
  .createContext('root')
@@ -2041,25 +1699,6 @@ export class Matterbridge extends EventEmitter {
2041
1699
  .createContext('root')
2042
1700
  .createContext('productDescription')
2043
1701
  .set('vendorId', await context.get('vendorId', 0xfff1));
2044
- /*
2045
- "Matterbridge.EndpointStructure": {
2046
- "unique_d60ca095a002f160-index_0": 1,
2047
- "unique_d60ca095a002f160-index_0-custom_Switch0": 2,
2048
- "unique_d60ca095a002f160-index_0-custom_Outlet0": 3,
2049
- "unique_d60ca095a002f160-index_0-custom_Light0": 4,
2050
- "unique_d60ca095a002f160-index_0-unique_7ddb4752b982ee108d5928e934f0fcfa": 2,
2051
- "unique_d60ca095a002f160-index_0-unique_7ddb4752b982ee108d5928e934f0fcfa-custom_PowerSource": 3,
2052
- "unique_d60ca095a002f160-index_0-unique_7ddb4752b982ee108d5928e934f0fcfa-custom_light:0": 4,
2053
- "unique_d60ca095a002f160-index_0-unique_7ddb4752b982ee108d5928e934f0fcfa-custom_light:1": 5,
2054
- "unique_d60ca095a002f160-index_0-unique_7ddb4752b982ee108d5928e934f0fcfa-custom_light:2": 6,
2055
- "unique_d60ca095a002f160-index_0-unique_7ddb4752b982ee108d5928e934f0fcfa-custom_light:3": 7,
2056
- "unique_d60ca095a002f160-index_0-unique_7ddb4752b982ee108d5928e934f0fcfa-custom_meter:0": 8,
2057
- "unique_d60ca095a002f160-index_0-unique_7ddb4752b982ee108d5928e934f0fcfa-custom_meter:1": 9,
2058
- "unique_d60ca095a002f160-index_0-unique_7ddb4752b982ee108d5928e934f0fcfa-custom_meter:2": 10,
2059
- "unique_d60ca095a002f160-index_0-unique_7ddb4752b982ee108d5928e934f0fcfa-custom_meter:3": 11,
2060
- "nextEndpointId": 5
2061
- },
2062
- */
2063
1702
  const rootDeviceName = (await context.get('deviceName', '')).replace(/[ .]/g, '');
2064
1703
  this.log.info(`Converting ${pluginName}.EndpointStructure to root.parts.${rootDeviceName}...`);
2065
1704
  for (const key of await endpointStructureContext.keys()) {
@@ -2138,12 +1777,6 @@ export class Matterbridge extends EventEmitter {
2138
1777
  this.log.error(`convertStorage error converting matter storage to Matterbridge edge for ${plg}${pluginName}${er}:`, error);
2139
1778
  }
2140
1779
  }
2141
- /**
2142
- * Makes a backup copy of the specified matter JSON storage file.
2143
- *
2144
- * @param storageName - The name of the JSON storage file to be backed up.
2145
- * @param backupName - The name of the backup file to be created.
2146
- */
2147
1780
  async backupMatterStorage(storageName, backupName) {
2148
1781
  try {
2149
1782
  this.log.debug(`Making backup copy of ${storageName}`);
@@ -2164,12 +1797,6 @@ export class Matterbridge extends EventEmitter {
2164
1797
  }
2165
1798
  }
2166
1799
  }
2167
- /**
2168
- * Restore the specified matter JSON storage file.
2169
- *
2170
- * @param backupName - The name of the backup file to restore from.
2171
- * @param storageName - The name of the JSON storage file to restored.
2172
- */
2173
1800
  async restoreMatterStorage(backupName, storageName) {
2174
1801
  try {
2175
1802
  this.log.notice(`Restoring the backup copy of ${storageName}`);
@@ -2190,10 +1817,6 @@ export class Matterbridge extends EventEmitter {
2190
1817
  }
2191
1818
  }
2192
1819
  }
2193
- /**
2194
- * Stops the matter storage.
2195
- * @returns {Promise<void>} A promise that resolves when the storage is stopped.
2196
- */
2197
1820
  async stopMatterStorage() {
2198
1821
  this.log.debug('Stopping storage');
2199
1822
  await this.storageManager?.close();
@@ -2202,14 +1825,8 @@ export class Matterbridge extends EventEmitter {
2202
1825
  this.matterbridgeContext = undefined;
2203
1826
  this.mattercontrollerContext = undefined;
2204
1827
  }
2205
- /**
2206
- * Creates a Matter server using the provided storage manager and the provided mdnsInterface.
2207
- * @param storageManager The storage manager to be used by the Matter server.
2208
- *
2209
- */
2210
1828
  async createMatterServer(storageManager) {
2211
1829
  this.log.debug('Creating matter server');
2212
- // Validate mdnsInterface
2213
1830
  if (this.mdnsInterface) {
2214
1831
  const networkInterfaces = os.networkInterfaces();
2215
1832
  const availableInterfaces = Object.keys(networkInterfaces);
@@ -2225,10 +1842,6 @@ export class Matterbridge extends EventEmitter {
2225
1842
  this.log.debug(`Created matter server with mdnsInterface: ${this.mdnsInterface ?? 'all available interfaces'}`);
2226
1843
  return matterServer;
2227
1844
  }
2228
- /**
2229
- * Starts the Matter server.
2230
- * If the Matter server is not initialized, it logs an error and performs cleanup.
2231
- */
2232
1845
  async startMatterServer() {
2233
1846
  if (!this.matterServer) {
2234
1847
  this.log.error('No matter server initialized');
@@ -2238,11 +1851,7 @@ export class Matterbridge extends EventEmitter {
2238
1851
  this.log.debug('Starting matter server...');
2239
1852
  await this.matterServer.start();
2240
1853
  this.log.debug('Started matter server');
2241
- // this.commissioningServer?.getRootEndpoint() && logEndpoint(this.commissioningServer?.getRootEndpoint());
2242
1854
  }
2243
- /**
2244
- * Stops the Matter server, commissioningServer and commissioningController.
2245
- */
2246
1855
  async stopMatterServer() {
2247
1856
  this.log.debug('Stopping matter commissioningServer');
2248
1857
  await this.commissioningServer?.close();
@@ -2256,35 +1865,23 @@ export class Matterbridge extends EventEmitter {
2256
1865
  this.matterAggregator = undefined;
2257
1866
  this.matterServer = undefined;
2258
1867
  }
2259
- /**
2260
- * Creates a Matter Aggregator.
2261
- * @param {StorageContext} context - The storage context.
2262
- * @returns {Aggregator} - The created Matter Aggregator.
2263
- */
2264
1868
  async createMatterAggregator(context, pluginName) {
2265
1869
  this.log.debug(`Creating matter aggregator for ${plg}${pluginName}${db}`);
2266
1870
  const matterAggregator = new Aggregator();
2267
1871
  return matterAggregator;
2268
1872
  }
2269
- /**
2270
- * Creates a matter commissioning server.
2271
- *
2272
- * @param {StorageContext} context - The storage context.
2273
- * @param {string} pluginName - The name of the commissioning server.
2274
- * @returns {CommissioningServer} The created commissioning server.
2275
- */
2276
1873
  async createCommisioningServer(context, pluginName) {
2277
1874
  this.log.debug(`Creating matter commissioning server for plugin ${plg}${pluginName}${db}`);
2278
1875
  const deviceName = await context.get('deviceName');
2279
1876
  const deviceType = await context.get('deviceType');
2280
1877
  const vendorId = await context.get('vendorId');
2281
- const vendorName = await context.get('vendorName'); // Home app = Manufacturer
1878
+ const vendorName = await context.get('vendorName');
2282
1879
  const productId = await context.get('productId');
2283
- const productName = await context.get('productName'); // Home app = Model
1880
+ const productName = await context.get('productName');
2284
1881
  const serialNumber = await context.get('serialNumber');
2285
1882
  const uniqueId = await context.get('uniqueId');
2286
1883
  const softwareVersion = await context.get('softwareVersion', 1);
2287
- const softwareVersionString = await context.get('softwareVersionString', '1.0.0'); // Home app = Firmware Revision
1884
+ const softwareVersionString = await context.get('softwareVersionString', '1.0.0');
2288
1885
  const hardwareVersion = await context.get('hardwareVersion', 1);
2289
1886
  const hardwareVersionString = await context.get('hardwareVersionString', '1.0.0');
2290
1887
  this.log.debug(`Creating matter commissioning server for plugin ${plg}${pluginName}${db} with deviceName '${deviceName}' deviceType ${deviceType}(0x${deviceType.toString(16).padStart(4, '0')})`);
@@ -2292,7 +1889,6 @@ export class Matterbridge extends EventEmitter {
2292
1889
  this.log.debug(`Creating matter commissioning server for plugin ${plg}${pluginName}${db} with softwareVersion ${softwareVersion} softwareVersionString ${softwareVersionString}`);
2293
1890
  this.log.debug(`Creating matter commissioning server for plugin ${plg}${pluginName}${db} with hardwareVersion ${hardwareVersion} hardwareVersionString ${hardwareVersionString}`);
2294
1891
  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} `);
2295
- // Validate ipv4address
2296
1892
  if (this.ipv4address) {
2297
1893
  const networkInterfaces = os.networkInterfaces();
2298
1894
  const availableAddresses = Object.values(networkInterfaces)
@@ -2307,7 +1903,6 @@ export class Matterbridge extends EventEmitter {
2307
1903
  this.log.info(`Using ipv4address '${this.ipv4address}' for the Matter commissioning server.`);
2308
1904
  }
2309
1905
  }
2310
- // Validate ipv6address
2311
1906
  if (this.ipv6address) {
2312
1907
  const networkInterfaces = os.networkInterfaces();
2313
1908
  const availableAddresses = Object.values(networkInterfaces)
@@ -2338,7 +1933,7 @@ export class Matterbridge extends EventEmitter {
2338
1933
  nodeLabel: productName,
2339
1934
  productLabel: productName,
2340
1935
  softwareVersion,
2341
- softwareVersionString, // Home app = Firmware Revision
1936
+ softwareVersionString,
2342
1937
  hardwareVersion,
2343
1938
  hardwareVersionString,
2344
1939
  uniqueId,
@@ -2434,24 +2029,6 @@ export class Matterbridge extends EventEmitter {
2434
2029
  commissioningServer.addCommandHandler('testEventTrigger', async ({ request: { enableKey, eventTrigger } }) => this.log.info(`testEventTrigger called on GeneralDiagnostic cluster: ${enableKey} ${eventTrigger}`));
2435
2030
  return commissioningServer;
2436
2031
  }
2437
- /**
2438
- * Creates a commissioning server storage context.
2439
- *
2440
- * @param pluginName - The name of the plugin.
2441
- * @param deviceName - The name of the device.
2442
- * @param deviceType - The type of the device.
2443
- * @param vendorId - The vendor ID.
2444
- * @param vendorName - The vendor name.
2445
- * @param productId - The product ID.
2446
- * @param productName - The product name.
2447
- * @param serialNumber - The serial number of the device (optional).
2448
- * @param uniqueId - The unique ID of the device (optional).
2449
- * @param softwareVersion - The software version of the device (optional).
2450
- * @param softwareVersionString - The software version string of the device (optional).
2451
- * @param hardwareVersion - The hardware version of the device (optional).
2452
- * @param hardwareVersionString - The hardware version string of the device (optional).
2453
- * @returns The storage context for the commissioning server.
2454
- */
2455
2032
  async createCommissioningServerContext(pluginName, deviceName, deviceType, vendorId, vendorName, productId, productName) {
2456
2033
  if (!this.storageManager)
2457
2034
  throw new Error('No storage manager initialized');
@@ -2479,13 +2056,6 @@ export class Matterbridge extends EventEmitter {
2479
2056
  this.log.debug(`- hardwareVersion: ${await storageContext.get('hardwareVersion')} hardwareVersionString: ${await storageContext.get('hardwareVersionString')}`);
2480
2057
  return storageContext;
2481
2058
  }
2482
- /**
2483
- * Imports the commissioning server context for a specific plugin and device.
2484
- * @param pluginName - The name of the plugin.
2485
- * @param device - The MatterbridgeDevice object representing the device.
2486
- * @returns The commissioning server context.
2487
- * @throws Error if the BasicInformationCluster is not found.
2488
- */
2489
2059
  async importCommissioningServerContext(pluginName, device) {
2490
2060
  this.log.debug(`Importing matter commissioning server storage context from device for ${plg}${pluginName}${db}`);
2491
2061
  const basic = device.getClusterServer(BasicInformationCluster);
@@ -2520,14 +2090,6 @@ export class Matterbridge extends EventEmitter {
2520
2090
  this.log.debug(`- hardwareVersion: ${await storageContext.get('hardwareVersion')} hardwareVersionString: ${await storageContext.get('hardwareVersionString')}`);
2521
2091
  return storageContext;
2522
2092
  }
2523
- /**
2524
- * Shows the commissioning server QR code for a given plugin.
2525
- * @param {CommissioningServer} commissioningServer - The commissioning server instance.
2526
- * @param {StorageContext} storageContext - The storage context instance.
2527
- * @param {NodeStorage} nodeContext - The node storage instance.
2528
- * @param {string} pluginName - The name of the plugin of Matterbridge in bridge mode.
2529
- * @returns {Promise<void>} - A promise that resolves when the QR code is shown.
2530
- */
2531
2093
  async showCommissioningQRCode(commissioningServer, storageContext, nodeContext, pluginName) {
2532
2094
  if (!commissioningServer || !storageContext || !nodeContext || !pluginName) {
2533
2095
  this.log.error(`showCommissioningQRCode error: commissioningServer: ${!commissioningServer} storageContext: ${!storageContext} nodeContext: ${!nodeContext} pluginName: ${pluginName}`);
@@ -2538,8 +2100,7 @@ export class Matterbridge extends EventEmitter {
2538
2100
  const { qrPairingCode, manualPairingCode } = commissioningServer.getPairingCode();
2539
2101
  const QrCode = new QrCodeSchema();
2540
2102
  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`);
2541
- // eslint-disable-next-line no-console
2542
- if (this.log.logLevel === "debug" /* LogLevel.DEBUG */ || this.log.logLevel === "info" /* LogLevel.INFO */)
2103
+ if (this.log.logLevel === "debug" || this.log.logLevel === "info")
2543
2104
  console.log(`${QrCode.encode(qrPairingCode)}\n`);
2544
2105
  this.log.info(`${plg}${pluginName}${nf} \n\nqrPairingCode: ${qrPairingCode} \n\nManual pairing code: ${manualPairingCode}\n`);
2545
2106
  if (pluginName === 'Matterbridge') {
@@ -2586,12 +2147,6 @@ export class Matterbridge extends EventEmitter {
2586
2147
  }
2587
2148
  this.wssSendRefreshRequired();
2588
2149
  }
2589
- /**
2590
- * Sanitizes the fabric information by converting bigint properties to string cause res.json doesn't know bigint.
2591
- *
2592
- * @param fabricInfo - The array of exposed fabric information objects.
2593
- * @returns An array of sanitized exposed fabric information objects.
2594
- */
2595
2150
  sanitizeFabricInformations(fabricInfo) {
2596
2151
  return fabricInfo.map((info) => {
2597
2152
  return {
@@ -2605,12 +2160,6 @@ export class Matterbridge extends EventEmitter {
2605
2160
  };
2606
2161
  });
2607
2162
  }
2608
- /**
2609
- * Sanitizes the session information by converting bigint properties to string.
2610
- *
2611
- * @param sessionInfo - The array of session information objects.
2612
- * @returns An array of sanitized session information objects.
2613
- */
2614
2163
  sanitizeSessionInformation(sessionInfo) {
2615
2164
  return sessionInfo
2616
2165
  .filter((session) => session.isPeerActive)
@@ -2638,12 +2187,6 @@ export class Matterbridge extends EventEmitter {
2638
2187
  };
2639
2188
  });
2640
2189
  }
2641
- /**
2642
- * Sets the reachability of a commissioning server and trigger.
2643
- *
2644
- * @param {CommissioningServer} commissioningServer - The commissioning server to set the reachability for.
2645
- * @param {boolean} reachable - The new reachability status.
2646
- */
2647
2190
  setCommissioningServerReachability(commissioningServer, reachable) {
2648
2191
  const basicInformationCluster = commissioningServer?.getRootClusterServer(BasicInformationCluster);
2649
2192
  if (basicInformationCluster && basicInformationCluster.attributes.reachable !== undefined)
@@ -2651,11 +2194,6 @@ export class Matterbridge extends EventEmitter {
2651
2194
  if (basicInformationCluster && basicInformationCluster.triggerReachableChangedEvent)
2652
2195
  basicInformationCluster.triggerReachableChangedEvent({ reachableNewValue: reachable });
2653
2196
  }
2654
- /**
2655
- * Sets the reachability of the specified matter aggregator and its bridged devices and trigger.
2656
- * @param {Aggregator} matterAggregator - The matter aggregator to set the reachability for.
2657
- * @param {boolean} reachable - A boolean indicating the reachability status to set.
2658
- */
2659
2197
  setAggregatorReachability(matterAggregator, reachable) {
2660
2198
  const basicInformationCluster = matterAggregator.getClusterServer(BasicInformationCluster);
2661
2199
  if (basicInformationCluster && basicInformationCluster.attributes.reachable !== undefined)
@@ -2668,12 +2206,6 @@ export class Matterbridge extends EventEmitter {
2668
2206
  device.getClusterServer(BridgedDeviceBasicInformationCluster)?.triggerReachableChangedEvent({ reachableNewValue: reachable });
2669
2207
  });
2670
2208
  }
2671
- /**
2672
- * Sets the reachability of a device and trigger.
2673
- *
2674
- * @param {MatterbridgeDevice} device - The device to set the reachability for.
2675
- * @param {boolean} reachable - The new reachability status of the device.
2676
- */
2677
2209
  setDeviceReachability(device, reachable) {
2678
2210
  const basicInformationCluster = device.getClusterServer(BasicInformationCluster);
2679
2211
  if (basicInformationCluster && basicInformationCluster.attributes.reachable !== undefined)
@@ -2722,10 +2254,6 @@ export class Matterbridge extends EventEmitter {
2722
2254
  }
2723
2255
  return vendorName;
2724
2256
  };
2725
- /**
2726
- * Retrieves the base registered plugins sanitized for res.json().
2727
- * @returns {BaseRegisteredPlugin[]} A promise that resolves to an array of BaseRegisteredPlugin objects.
2728
- */
2729
2257
  async getBaseRegisteredPlugins() {
2730
2258
  const baseRegisteredPlugins = [];
2731
2259
  for (const plugin of this.plugins) {
@@ -2757,36 +2285,13 @@ export class Matterbridge extends EventEmitter {
2757
2285
  }
2758
2286
  return baseRegisteredPlugins;
2759
2287
  }
2760
- /**
2761
- * Spawns a child process with the given command and arguments.
2762
- * @param {string} command - The command to execute.
2763
- * @param {string[]} args - The arguments to pass to the command (default: []).
2764
- * @returns {Promise<boolean>} A promise that resolves when the child process exits successfully, or rejects if there is an error.
2765
- */
2766
2288
  async spawnCommand(command, args = []) {
2767
- /*
2768
- npm > npm.cmd on windows
2769
- cmd.exe ['dir'] on windows
2770
- await this.spawnCommand('npm', ['install', '-g', 'matterbridge']);
2771
- process.on('unhandledRejection', (reason, promise) => {
2772
- this.log.error('Unhandled Rejection at:', promise, 'reason:', reason);
2773
- });
2774
-
2775
- spawn - [14:27:21.125] [Matterbridge:spawn]: changed 38 packages in 4s
2776
- spawn - [14:27:21.125] [Matterbridge:spawn]: 10 packages are looking for funding run `npm fund` for details
2777
- debug - [14:27:21.131] [Matterbridge]: Child process exited with code 0 and signal null
2778
- debug - [14:27:21.131] [Matterbridge]: Child process stdio streams have closed with code 0
2779
- */
2780
2289
  const cmdLine = command + ' ' + args.join(' ');
2781
2290
  if (process.platform === 'win32' && command === 'npm') {
2782
- // Must be spawn('cmd.exe', ['/c', 'npm -g install <package>']);
2783
2291
  const argstring = 'npm ' + args.join(' ');
2784
2292
  args.splice(0, args.length, '/c', argstring);
2785
2293
  command = 'cmd.exe';
2786
2294
  }
2787
- // Decide when using sudo on linux
2788
- // When you need sudo: Spawn stderr: npm error Error: EACCES: permission denied
2789
- // When you don't need sudo: Failed to start child process "npm install -g matterbridge-eve-door": spawn sudo ENOENT
2790
2295
  if (hasParameter('sudo') || (process.platform === 'linux' && command === 'npm' && !hasParameter('docker') && !hasParameter('nosudo'))) {
2791
2296
  args.unshift(command);
2792
2297
  command = 'sudo';
@@ -2844,102 +2349,55 @@ export class Matterbridge extends EventEmitter {
2844
2349
  }
2845
2350
  });
2846
2351
  }
2847
- /**
2848
- * Sends a WebSocket message to all connected clients.
2849
- *
2850
- * @param {string} level - The logger level of the message: debug info notice warn error fatal...
2851
- * @param {string} time - The time string of the message
2852
- * @param {string} name - The logger name of the message
2853
- * @param {string} message - The content of the message.
2854
- */
2855
2352
  wssSendMessage(level, time, name, message) {
2856
2353
  if (!level || !time || !name || !message)
2857
2354
  return;
2858
- // Remove ANSI escape codes from the message
2859
- // eslint-disable-next-line no-control-regex
2860
2355
  message = message.replace(/\x1B\[[0-9;]*[m|s|u|K]/g, '');
2861
- // Remove leading asterisks from the message
2862
2356
  message = message.replace(/^\*+/, '');
2863
- // Replace all occurrences of \t and \n
2864
2357
  message = message.replace(/[\t\n]/g, '');
2865
- // Remove non-printable characters
2866
- // eslint-disable-next-line no-control-regex
2867
2358
  message = message.replace(/[\x00-\x1F\x7F]/g, '');
2868
- // Replace all occurrences of \" with "
2869
2359
  message = message.replace(/\\"/g, '"');
2870
- // Define the maximum allowed length for continuous characters without a space
2871
2360
  const maxContinuousLength = 100;
2872
2361
  const keepStartLength = 20;
2873
2362
  const keepEndLength = 20;
2874
- // Split the message into words
2875
2363
  message = message
2876
2364
  .split(' ')
2877
2365
  .map((word) => {
2878
- // If the word length exceeds the max continuous length, insert spaces and truncate
2879
2366
  if (word.length > maxContinuousLength) {
2880
2367
  return word.slice(0, keepStartLength) + ' ... ' + word.slice(-keepEndLength);
2881
2368
  }
2882
2369
  return word;
2883
2370
  })
2884
2371
  .join(' ');
2885
- // Send the message to all connected clients
2886
2372
  this.webSocketServer?.clients.forEach((client) => {
2887
2373
  if (client.readyState === WebSocket.OPEN) {
2888
2374
  client.send(JSON.stringify({ id: WS_ID_LOG, src: 'Matterbridge', level, time, name, message }));
2889
2375
  }
2890
2376
  });
2891
2377
  }
2892
- /**
2893
- * Sends a need to refresh WebSocket message to all connected clients.
2894
- *
2895
- */
2896
2378
  wssSendRefreshRequired() {
2897
2379
  this.matterbridgeInformation.refreshRequired = true;
2898
- // Send the message to all connected clients
2899
2380
  this.webSocketServer?.clients.forEach((client) => {
2900
2381
  if (client.readyState === WebSocket.OPEN) {
2901
2382
  client.send(JSON.stringify({ id: WS_ID_REFRESH_NEEDED, src: 'Matterbridge', dst: 'Frontend', method: 'refresh_required', params: {} }));
2902
2383
  }
2903
2384
  });
2904
2385
  }
2905
- /**
2906
- * Sends a need to restart WebSocket message to all connected clients.
2907
- *
2908
- */
2909
2386
  wssSendRestartRequired() {
2910
2387
  this.matterbridgeInformation.restartRequired = true;
2911
- // Send the message to all connected clients
2912
2388
  this.webSocketServer?.clients.forEach((client) => {
2913
2389
  if (client.readyState === WebSocket.OPEN) {
2914
2390
  client.send(JSON.stringify({ id: WS_ID_RESTART_NEEDED, src: 'Matterbridge', dst: 'Frontend', method: 'restart_required', params: {} }));
2915
2391
  }
2916
2392
  });
2917
2393
  }
2918
- /**
2919
- * Initializes the frontend of Matterbridge.
2920
- *
2921
- * @param port The port number to run the frontend server on. Default is 8283.
2922
- */
2923
2394
  async initializeFrontend(port = 8283) {
2924
2395
  let initializeError = false;
2925
2396
  this.log.debug(`Initializing the frontend ${hasParameter('ssl') ? 'https' : 'http'} server on port ${YELLOW}${port}${db}`);
2926
- // Create the express app that serves the frontend
2927
2397
  this.expressApp = express();
2928
- // Log all requests to the server for debugging
2929
- /*
2930
- if (hasParameter('homedir')) {
2931
- this.expressApp.use((req, res, next) => {
2932
- this.log.debug(`Received request on expressApp: ${req.method} ${req.url}`);
2933
- next();
2934
- });
2935
- }
2936
- */
2937
- // Serve static files from '/static' endpoint
2938
2398
  this.expressApp.use(express.static(path.join(this.rootDirectory, 'frontend/build')));
2939
2399
  if (!hasParameter('ssl')) {
2940
- // Create an HTTP server and attach the express app
2941
2400
  this.httpServer = createServer(this.expressApp);
2942
- // Listen on the specified port
2943
2401
  if (hasParameter('ingress')) {
2944
2402
  this.httpServer.listen(port, '0.0.0.0', () => {
2945
2403
  this.log.info(`The frontend http server is listening on ${UNDERLINE}http://0.0.0.0:${port}${UNDERLINEOFF}${rs}`);
@@ -2953,7 +2411,6 @@ export class Matterbridge extends EventEmitter {
2953
2411
  this.log.info(`The frontend http server is listening on ${UNDERLINE}http://[${this.systemInformation.ipv6Address}]:${port}${UNDERLINEOFF}${rs}`);
2954
2412
  });
2955
2413
  }
2956
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
2957
2414
  this.httpServer.on('error', (error) => {
2958
2415
  this.log.error(`Frontend http server error listening on ${port}`);
2959
2416
  switch (error.code) {
@@ -2969,7 +2426,6 @@ export class Matterbridge extends EventEmitter {
2969
2426
  });
2970
2427
  }
2971
2428
  else {
2972
- // Load the SSL certificate, the private key and optionally the CA certificate
2973
2429
  let cert;
2974
2430
  try {
2975
2431
  cert = await fs.readFile(path.join(this.matterbridgeDirectory, 'certs/cert.pem'), 'utf8');
@@ -2997,9 +2453,7 @@ export class Matterbridge extends EventEmitter {
2997
2453
  this.log.info(`CA certificate file ${path.join(this.matterbridgeDirectory, 'certs/ca.pem')} not loaded: ${error}`);
2998
2454
  }
2999
2455
  const serverOptions = { cert, key, ca };
3000
- // Create an HTTPS server with the SSL certificate and private key (ca is optional) and attach the express app
3001
2456
  this.httpsServer = https.createServer(serverOptions, this.expressApp);
3002
- // Listen on the specified port
3003
2457
  if (hasParameter('ingress')) {
3004
2458
  this.httpsServer.listen(port, '0.0.0.0', () => {
3005
2459
  this.log.info(`The frontend https server is listening on ${UNDERLINE}https://0.0.0.0:${port}${UNDERLINEOFF}${rs}`);
@@ -3013,7 +2467,6 @@ export class Matterbridge extends EventEmitter {
3013
2467
  this.log.info(`The frontend https server is listening on ${UNDERLINE}https://[${this.systemInformation.ipv6Address}]:${port}${UNDERLINEOFF}${rs}`);
3014
2468
  });
3015
2469
  }
3016
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
3017
2470
  this.httpsServer.on('error', (error) => {
3018
2471
  this.log.error(`Frontend https server error listening on ${port}`);
3019
2472
  switch (error.code) {
@@ -3030,13 +2483,12 @@ export class Matterbridge extends EventEmitter {
3030
2483
  }
3031
2484
  if (initializeError)
3032
2485
  return;
3033
- // Createe a WebSocket server and attach it to the http or https server
3034
2486
  const wssPort = port;
3035
2487
  const wssHost = hasParameter('ssl') ? `wss://${this.systemInformation.ipv4Address}:${wssPort}` : `ws://${this.systemInformation.ipv4Address}:${wssPort}`;
3036
2488
  this.webSocketServer = new WebSocketServer(hasParameter('ssl') ? { server: this.httpsServer } : { server: this.httpServer });
3037
2489
  this.webSocketServer.on('connection', (ws, request) => {
3038
2490
  const clientIp = request.socket.remoteAddress;
3039
- AnsiLogger.setGlobalCallback(this.wssSendMessage.bind(this), "debug" /* LogLevel.DEBUG */);
2491
+ AnsiLogger.setGlobalCallback(this.wssSendMessage.bind(this), "debug");
3040
2492
  this.log.info(`WebSocketServer client "${clientIp}" connected to Matterbridge`);
3041
2493
  ws.on('message', (message) => {
3042
2494
  this.log.debug(`WebSocket client message: ${message}`);
@@ -3069,7 +2521,6 @@ export class Matterbridge extends EventEmitter {
3069
2521
  this.webSocketServer.on('error', (ws, error) => {
3070
2522
  this.log.error(`WebSocketServer error: ${error}`);
3071
2523
  });
3072
- // Endpoint to validate login code
3073
2524
  this.expressApp.post('/api/login', express.json(), async (req, res) => {
3074
2525
  const { password } = req.body;
3075
2526
  this.log.debug('The frontend sent /api/login', password);
@@ -3088,14 +2539,12 @@ export class Matterbridge extends EventEmitter {
3088
2539
  this.log.warn('/api/login error wrong password');
3089
2540
  res.json({ valid: false });
3090
2541
  }
3091
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
3092
2542
  }
3093
2543
  catch (error) {
3094
2544
  this.log.error('/api/login error getting password');
3095
2545
  res.json({ valid: false });
3096
2546
  }
3097
2547
  });
3098
- // Endpoint to provide settings
3099
2548
  this.expressApp.get('/api/settings', express.json(), async (req, res) => {
3100
2549
  this.log.debug('The frontend sent /api/settings');
3101
2550
  this.matterbridgeInformation.bridgeMode = this.bridgeMode;
@@ -3116,17 +2565,13 @@ export class Matterbridge extends EventEmitter {
3116
2565
  this.matterbridgeInformation.matterbridgeSessionInformations = Array.from(this.matterbridgeSessionInformations.values());
3117
2566
  this.matterbridgeInformation.profile = this.profile;
3118
2567
  const response = { systemInformation: this.systemInformation, matterbridgeInformation: this.matterbridgeInformation };
3119
- // this.log.debug('Response:', debugStringify(response));
3120
2568
  res.json(response);
3121
2569
  });
3122
- // Endpoint to provide plugins
3123
2570
  this.expressApp.get('/api/plugins', async (req, res) => {
3124
2571
  this.log.debug('The frontend sent /api/plugins');
3125
2572
  const response = await this.getBaseRegisteredPlugins();
3126
- // this.log.debug('Response:', debugStringify(response));
3127
2573
  res.json(response);
3128
2574
  });
3129
- // Endpoint to provide devices
3130
2575
  this.expressApp.get('/api/devices', (req, res) => {
3131
2576
  this.log.debug('The frontend sent /api/devices');
3132
2577
  const devices = [];
@@ -3159,10 +2604,8 @@ export class Matterbridge extends EventEmitter {
3159
2604
  cluster: cluster,
3160
2605
  });
3161
2606
  });
3162
- // this.log.debug('Response:', debugStringify(data));
3163
2607
  res.json(devices);
3164
2608
  });
3165
- // Endpoint to provide the cluster servers of the devices
3166
2609
  this.expressApp.get('/api/devices_clusters/:selectedPluginName/:selectedDeviceEndpoint', (req, res) => {
3167
2610
  const selectedPluginName = req.params.selectedPluginName;
3168
2611
  const selectedDeviceEndpoint = parseInt(req.params.selectedDeviceEndpoint, 10);
@@ -3182,7 +2625,6 @@ export class Matterbridge extends EventEmitter {
3182
2625
  Object.entries(clusterServer.attributes).forEach(([key, value]) => {
3183
2626
  if (clusterServer.name === 'EveHistory')
3184
2627
  return;
3185
- // this.log.debug(`***--clusterServer: ${clusterServer.name}(${clusterServer.id}) attribute:${key}(${value.id}) ${value.isFixed} ${value.isWritable} ${value.isWritable}`);
3186
2628
  let attributeValue;
3187
2629
  try {
3188
2630
  if (typeof value.getLocal() === 'object')
@@ -3193,7 +2635,6 @@ export class Matterbridge extends EventEmitter {
3193
2635
  catch (error) {
3194
2636
  attributeValue = 'Fabric-Scoped';
3195
2637
  this.log.debug(`GetLocal value ${error} in clusterServer: ${clusterServer.name}(${clusterServer.id}) attribute: ${key}(${value.id})`);
3196
- // console.log(error);
3197
2638
  }
3198
2639
  data.push({
3199
2640
  endpoint: device.number ? device.number.toString() : '...',
@@ -3206,14 +2647,12 @@ export class Matterbridge extends EventEmitter {
3206
2647
  });
3207
2648
  });
3208
2649
  device.getChildEndpoints().forEach((childEndpoint) => {
3209
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
3210
2650
  const name = this.edge ? childEndpoint.endpoint?.id : childEndpoint.uniqueStorageKey;
3211
2651
  const clusterServers = childEndpoint.getAllClusterServers();
3212
2652
  clusterServers.forEach((clusterServer) => {
3213
2653
  Object.entries(clusterServer.attributes).forEach(([key, value]) => {
3214
2654
  if (clusterServer.name === 'EveHistory')
3215
2655
  return;
3216
- // this.log.debug(`***--clusterServer: ${clusterServer.name}(${clusterServer.id}) attribute:${key}(${value.id}) ${value.isFixed} ${value.isWritable} ${value.isWritable}`);
3217
2656
  let attributeValue;
3218
2657
  try {
3219
2658
  if (typeof value.getLocal() === 'object')
@@ -3224,7 +2663,6 @@ export class Matterbridge extends EventEmitter {
3224
2663
  catch (error) {
3225
2664
  attributeValue = 'Unavailable';
3226
2665
  this.log.debug(`GetLocal error ${error} in clusterServer: ${clusterServer.name}(${clusterServer.id}) attribute: ${key}(${value.id})`);
3227
- // console.log(error);
3228
2666
  }
3229
2667
  data.push({
3230
2668
  endpoint: (childEndpoint.number ? childEndpoint.number.toString() : '...') + (name ? ' (' + name + ')' : ''),
@@ -3241,7 +2679,6 @@ export class Matterbridge extends EventEmitter {
3241
2679
  });
3242
2680
  res.json(data);
3243
2681
  });
3244
- // Endpoint to view the log
3245
2682
  this.expressApp.get('/api/view-log', async (req, res) => {
3246
2683
  this.log.debug('The frontend sent /api/log');
3247
2684
  try {
@@ -3254,12 +2691,10 @@ export class Matterbridge extends EventEmitter {
3254
2691
  res.status(500).send('Error reading log file');
3255
2692
  }
3256
2693
  });
3257
- // Endpoint to download the matterbridge log
3258
2694
  this.expressApp.get('/api/download-mblog', async (req, res) => {
3259
2695
  this.log.debug('The frontend sent /api/download-mblog');
3260
2696
  try {
3261
2697
  await fs.access(path.join(this.matterbridgeDirectory, this.matterbrideLoggerFile), fs.constants.F_OK);
3262
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
3263
2698
  }
3264
2699
  catch (error) {
3265
2700
  fs.appendFile(path.join(this.matterbridgeDirectory, this.matterbrideLoggerFile), 'Enable the log on file in the settings to enable the file logger');
@@ -3271,12 +2706,10 @@ export class Matterbridge extends EventEmitter {
3271
2706
  }
3272
2707
  });
3273
2708
  });
3274
- // Endpoint to download the matter log
3275
2709
  this.expressApp.get('/api/download-mjlog', async (req, res) => {
3276
2710
  this.log.debug('The frontend sent /api/download-mjlog');
3277
2711
  try {
3278
2712
  await fs.access(path.join(this.matterbridgeDirectory, this.matterLoggerFile), fs.constants.F_OK);
3279
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
3280
2713
  }
3281
2714
  catch (error) {
3282
2715
  fs.appendFile(path.join(this.matterbridgeDirectory, this.matterLoggerFile), 'Enable the log on file in the settings to enable the file logger');
@@ -3288,7 +2721,6 @@ export class Matterbridge extends EventEmitter {
3288
2721
  }
3289
2722
  });
3290
2723
  });
3291
- // Endpoint to download the matter storage file
3292
2724
  this.expressApp.get('/api/download-mjstorage', (req, res) => {
3293
2725
  this.log.debug('The frontend sent /api/download-mjstorage');
3294
2726
  res.download(path.join(this.matterbridgeDirectory, this.matterStorageName), 'matterbridge.json', (error) => {
@@ -3298,7 +2730,6 @@ export class Matterbridge extends EventEmitter {
3298
2730
  }
3299
2731
  });
3300
2732
  });
3301
- // Endpoint to download the matterbridge storage directory
3302
2733
  this.expressApp.get('/api/download-mbstorage', async (req, res) => {
3303
2734
  this.log.debug('The frontend sent /api/download-mbstorage');
3304
2735
  await createZip(path.join(os.tmpdir(), `matterbridge.${this.nodeStorageName}.zip`), path.join(this.matterbridgeDirectory, this.nodeStorageName));
@@ -3309,7 +2740,6 @@ export class Matterbridge extends EventEmitter {
3309
2740
  }
3310
2741
  });
3311
2742
  });
3312
- // Endpoint to download the matterbridge plugin directory
3313
2743
  this.expressApp.get('/api/download-pluginstorage', async (req, res) => {
3314
2744
  this.log.debug('The frontend sent /api/download-pluginstorage');
3315
2745
  await createZip(path.join(os.tmpdir(), `matterbridge.pluginstorage.zip`), this.matterbridgePluginDirectory);
@@ -3320,11 +2750,9 @@ export class Matterbridge extends EventEmitter {
3320
2750
  }
3321
2751
  });
3322
2752
  });
3323
- // Endpoint to download the matterbridge plugin config files
3324
2753
  this.expressApp.get('/api/download-pluginconfig', async (req, res) => {
3325
2754
  this.log.debug('The frontend sent /api/download-pluginconfig');
3326
2755
  await createZip(path.join(os.tmpdir(), `matterbridge.pluginconfig.zip`), path.relative(process.cwd(), path.join(this.matterbridgeDirectory, '*.config.json')));
3327
- // 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')));
3328
2756
  res.download(path.join(os.tmpdir(), `matterbridge.pluginconfig.zip`), `matterbridge.pluginconfig.zip`, (error) => {
3329
2757
  if (error) {
3330
2758
  this.log.error(`Error downloading file matterbridge.pluginstorage.zip: ${error instanceof Error ? error.message : error}`);
@@ -3332,7 +2760,6 @@ export class Matterbridge extends EventEmitter {
3332
2760
  }
3333
2761
  });
3334
2762
  });
3335
- // Endpoint to download the matterbridge plugin config files
3336
2763
  this.expressApp.get('/api/download-backup', async (req, res) => {
3337
2764
  this.log.debug('The frontend sent /api/download-backup');
3338
2765
  res.download(path.join(os.tmpdir(), `matterbridge.backup.zip`), `matterbridge.backup.zip`, (error) => {
@@ -3342,7 +2769,6 @@ export class Matterbridge extends EventEmitter {
3342
2769
  }
3343
2770
  });
3344
2771
  });
3345
- // Endpoint to receive commands
3346
2772
  this.expressApp.post('/api/command/:command/:param', express.json(), async (req, res) => {
3347
2773
  const command = req.params.command;
3348
2774
  let param = req.params.param;
@@ -3352,15 +2778,13 @@ export class Matterbridge extends EventEmitter {
3352
2778
  return;
3353
2779
  }
3354
2780
  this.log.debug(`Received frontend command: ${command}:${param}`);
3355
- // Handle the command setpassword from Settings
3356
2781
  if (command === 'setpassword') {
3357
- const password = param.slice(1, -1); // Remove the first and last characters
2782
+ const password = param.slice(1, -1);
3358
2783
  this.log.debug('setpassword', param, password);
3359
2784
  await this.nodeContext?.set('password', password);
3360
2785
  res.json({ message: 'Command received' });
3361
2786
  return;
3362
2787
  }
3363
- // Handle the command setbridgemode from Settings
3364
2788
  if (command === 'setbridgemode') {
3365
2789
  this.log.debug(`setbridgemode: ${param}`);
3366
2790
  this.wssSendRestartRequired();
@@ -3368,7 +2792,6 @@ export class Matterbridge extends EventEmitter {
3368
2792
  res.json({ message: 'Command received' });
3369
2793
  return;
3370
2794
  }
3371
- // Handle the command backup from Settings
3372
2795
  if (command === 'backup') {
3373
2796
  this.log.notice(`Prepairing the backup...`);
3374
2797
  await createZip(path.join(os.tmpdir(), `matterbridge.backup.zip`), path.join(this.matterbridgeDirectory), path.join(this.matterbridgePluginDirectory));
@@ -3376,26 +2799,25 @@ export class Matterbridge extends EventEmitter {
3376
2799
  res.json({ message: 'Command received' });
3377
2800
  return;
3378
2801
  }
3379
- // Handle the command setmbloglevel from Settings
3380
2802
  if (command === 'setmbloglevel') {
3381
2803
  this.log.debug('Matterbridge log level:', param);
3382
2804
  if (param === 'Debug') {
3383
- this.log.logLevel = "debug" /* LogLevel.DEBUG */;
2805
+ this.log.logLevel = "debug";
3384
2806
  }
3385
2807
  else if (param === 'Info') {
3386
- this.log.logLevel = "info" /* LogLevel.INFO */;
2808
+ this.log.logLevel = "info";
3387
2809
  }
3388
2810
  else if (param === 'Notice') {
3389
- this.log.logLevel = "notice" /* LogLevel.NOTICE */;
2811
+ this.log.logLevel = "notice";
3390
2812
  }
3391
2813
  else if (param === 'Warn') {
3392
- this.log.logLevel = "warn" /* LogLevel.WARN */;
2814
+ this.log.logLevel = "warn";
3393
2815
  }
3394
2816
  else if (param === 'Error') {
3395
- this.log.logLevel = "error" /* LogLevel.ERROR */;
2817
+ this.log.logLevel = "error";
3396
2818
  }
3397
2819
  else if (param === 'Fatal') {
3398
- this.log.logLevel = "fatal" /* LogLevel.FATAL */;
2820
+ this.log.logLevel = "fatal";
3399
2821
  }
3400
2822
  await this.nodeContext?.set('matterbridgeLogLevel', this.log.logLevel);
3401
2823
  MatterbridgeDevice.logLevel = this.log.logLevel;
@@ -3403,13 +2825,12 @@ export class Matterbridge extends EventEmitter {
3403
2825
  for (const plugin of this.plugins) {
3404
2826
  if (!plugin.platform || !plugin.platform.config)
3405
2827
  continue;
3406
- plugin.platform.log.logLevel = plugin.platform.config.debug ? "debug" /* LogLevel.DEBUG */ : this.log.logLevel;
3407
- await plugin.platform.onChangeLoggerLevel(plugin.platform.config.debug ? "debug" /* LogLevel.DEBUG */ : this.log.logLevel);
2828
+ plugin.platform.log.logLevel = plugin.platform.config.debug ? "debug" : this.log.logLevel;
2829
+ await plugin.platform.onChangeLoggerLevel(plugin.platform.config.debug ? "debug" : this.log.logLevel);
3408
2830
  }
3409
2831
  res.json({ message: 'Command received' });
3410
2832
  return;
3411
2833
  }
3412
- // Handle the command setmbloglevel from Settings
3413
2834
  if (command === 'setmjloglevel') {
3414
2835
  this.log.debug('Matter.js log level:', param);
3415
2836
  if (param === 'Debug') {
@@ -3434,34 +2855,30 @@ export class Matterbridge extends EventEmitter {
3434
2855
  res.json({ message: 'Command received' });
3435
2856
  return;
3436
2857
  }
3437
- // Handle the command setmdnsinterface from Settings
3438
2858
  if (command === 'setmdnsinterface') {
3439
- param = param.slice(1, -1); // Remove the first and last characters *mdns*
2859
+ param = param.slice(1, -1);
3440
2860
  this.matterbridgeInformation.mattermdnsinterface = param;
3441
2861
  this.log.debug('Matter.js mdns interface:', param === '' ? 'All interfaces' : param);
3442
2862
  await this.nodeContext?.set('mattermdnsinterface', param);
3443
2863
  res.json({ message: 'Command received' });
3444
2864
  return;
3445
2865
  }
3446
- // Handle the command setipv4address from Settings
3447
2866
  if (command === 'setipv4address') {
3448
- param = param.slice(1, -1); // Remove the first and last characters *ip*
2867
+ param = param.slice(1, -1);
3449
2868
  this.matterbridgeInformation.matteripv4address = param;
3450
2869
  this.log.debug('Matter.js ipv4 address:', param === '' ? 'All ipv4 addresses' : param);
3451
2870
  await this.nodeContext?.set('matteripv4address', param);
3452
2871
  res.json({ message: 'Command received' });
3453
2872
  return;
3454
2873
  }
3455
- // Handle the command setipv6address from Settings
3456
2874
  if (command === 'setipv6address') {
3457
- param = param.slice(1, -1); // Remove the first and last characters *ip*
2875
+ param = param.slice(1, -1);
3458
2876
  this.matterbridgeInformation.matteripv6address = param;
3459
2877
  this.log.debug('Matter.js ipv6 address:', param === '' ? 'All ipv6 addresses' : param);
3460
2878
  await this.nodeContext?.set('matteripv6address', param);
3461
2879
  res.json({ message: 'Command received' });
3462
2880
  return;
3463
2881
  }
3464
- // Handle the command setmatterport from Settings
3465
2882
  if (command === 'setmatterport') {
3466
2883
  const port = Math.min(Math.max(parseInt(param), 5540), 5560);
3467
2884
  this.matterbridgeInformation.matterPort = port;
@@ -3470,7 +2887,6 @@ export class Matterbridge extends EventEmitter {
3470
2887
  res.json({ message: 'Command received' });
3471
2888
  return;
3472
2889
  }
3473
- // Handle the command setmatterdiscriminator from Settings
3474
2890
  if (command === 'setmatterdiscriminator') {
3475
2891
  const discriminator = Math.min(Math.max(parseInt(param), 1000), 4095);
3476
2892
  this.matterbridgeInformation.matterDiscriminator = discriminator;
@@ -3479,7 +2895,6 @@ export class Matterbridge extends EventEmitter {
3479
2895
  res.json({ message: 'Command received' });
3480
2896
  return;
3481
2897
  }
3482
- // Handle the command setmatterpasscode from Settings
3483
2898
  if (command === 'setmatterpasscode') {
3484
2899
  const passcode = Math.min(Math.max(parseInt(param), 10000000), 90000000);
3485
2900
  this.matterbridgeInformation.matterPasscode = passcode;
@@ -3488,20 +2903,17 @@ export class Matterbridge extends EventEmitter {
3488
2903
  res.json({ message: 'Command received' });
3489
2904
  return;
3490
2905
  }
3491
- // Handle the command setmbloglevel from Settings
3492
2906
  if (command === 'setmblogfile') {
3493
2907
  this.log.debug('Matterbridge file log:', param);
3494
2908
  this.matterbridgeInformation.fileLogger = param === 'true';
3495
2909
  await this.nodeContext?.set('matterbridgeFileLog', param === 'true');
3496
- // Create the file logger for matterbridge
3497
2910
  if (param === 'true')
3498
- AnsiLogger.setGlobalLogfile(path.join(this.matterbridgeDirectory, this.matterbrideLoggerFile), "debug" /* LogLevel.DEBUG */, true);
2911
+ AnsiLogger.setGlobalLogfile(path.join(this.matterbridgeDirectory, this.matterbrideLoggerFile), "debug", true);
3499
2912
  else
3500
2913
  AnsiLogger.setGlobalLogfile(undefined);
3501
2914
  res.json({ message: 'Command received' });
3502
2915
  return;
3503
2916
  }
3504
- // Handle the command setmbloglevel from Settings
3505
2917
  if (command === 'setmjlogfile') {
3506
2918
  this.log.debug('Matter file log:', param);
3507
2919
  this.matterbridgeInformation.matterFileLogger = param === 'true';
@@ -3528,43 +2940,36 @@ export class Matterbridge extends EventEmitter {
3528
2940
  res.json({ message: 'Command received' });
3529
2941
  return;
3530
2942
  }
3531
- // Handle the command unregister from Settings
3532
2943
  if (command === 'unregister') {
3533
2944
  await this.unregisterAndShutdownProcess();
3534
2945
  res.json({ message: 'Command received' });
3535
2946
  return;
3536
2947
  }
3537
- // Handle the command reset from Settings
3538
2948
  if (command === 'reset') {
3539
2949
  await this.shutdownProcessAndReset();
3540
2950
  res.json({ message: 'Command received' });
3541
2951
  return;
3542
2952
  }
3543
- // Handle the command factoryreset from Settings
3544
2953
  if (command === 'factoryreset') {
3545
2954
  await this.shutdownProcessAndFactoryReset();
3546
2955
  res.json({ message: 'Command received' });
3547
2956
  return;
3548
2957
  }
3549
- // Handle the command shutdown from Header
3550
2958
  if (command === 'shutdown') {
3551
2959
  await this.shutdownProcess();
3552
2960
  res.json({ message: 'Command received' });
3553
2961
  return;
3554
2962
  }
3555
- // Handle the command restart from Header
3556
2963
  if (command === 'restart') {
3557
2964
  await this.restartProcess();
3558
2965
  res.json({ message: 'Command received' });
3559
2966
  return;
3560
2967
  }
3561
- // Handle the command update from Header
3562
2968
  if (command === 'update') {
3563
2969
  this.log.info('Updating matterbridge...');
3564
2970
  try {
3565
2971
  await this.spawnCommand('npm', ['install', '-g', 'matterbridge', '--omit=dev', '--verbose']);
3566
2972
  this.log.info('Matterbridge has been updated. Full restart required.');
3567
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
3568
2973
  }
3569
2974
  catch (error) {
3570
2975
  this.log.error('Error updating matterbridge');
@@ -3574,11 +2979,9 @@ export class Matterbridge extends EventEmitter {
3574
2979
  res.json({ message: 'Command received' });
3575
2980
  return;
3576
2981
  }
3577
- // Handle the command saveconfig from Home
3578
2982
  if (command === 'saveconfig') {
3579
2983
  param = param.replace(/\*/g, '\\');
3580
2984
  this.log.info(`Saving config for plugin ${plg}${param}${nf}...`);
3581
- // console.log('Req.body:', JSON.stringify(req.body, null, 2));
3582
2985
  if (!this.plugins.has(param)) {
3583
2986
  this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
3584
2987
  }
@@ -3592,39 +2995,33 @@ export class Matterbridge extends EventEmitter {
3592
2995
  res.json({ message: 'Command received' });
3593
2996
  return;
3594
2997
  }
3595
- // Handle the command installplugin from Home
3596
2998
  if (command === 'installplugin') {
3597
2999
  param = param.replace(/\*/g, '\\');
3598
3000
  this.log.info(`Installing plugin ${plg}${param}${nf}...`);
3599
3001
  try {
3600
3002
  await this.spawnCommand('npm', ['install', '-g', param, '--omit=dev', '--verbose']);
3601
3003
  this.log.info(`Plugin ${plg}${param}${nf} installed. Full restart required.`);
3602
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
3603
3004
  }
3604
3005
  catch (error) {
3605
3006
  this.log.error(`Error installing plugin ${plg}${param}${er}`);
3606
3007
  }
3607
3008
  this.wssSendRestartRequired();
3608
3009
  param = param.split('@')[0];
3609
- // Also add the plugin to matterbridge so no return!
3610
3010
  if (param === 'matterbridge') {
3611
- // 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
3612
3011
  res.json({ message: 'Command received' });
3613
3012
  return;
3614
3013
  }
3615
3014
  }
3616
- // Handle the command addplugin from Home
3617
3015
  if (command === 'addplugin' || command === 'installplugin') {
3618
3016
  param = param.replace(/\*/g, '\\');
3619
3017
  const plugin = await this.plugins.add(param);
3620
3018
  if (plugin) {
3621
- this.plugins.load(plugin, true, 'The plugin has been added', true); // No await do it in the background
3019
+ this.plugins.load(plugin, true, 'The plugin has been added', true);
3622
3020
  }
3623
3021
  res.json({ message: 'Command received' });
3624
3022
  this.wssSendRefreshRequired();
3625
3023
  return;
3626
3024
  }
3627
- // Handle the command removeplugin from Home
3628
3025
  if (command === 'removeplugin') {
3629
3026
  if (!this.plugins.has(param)) {
3630
3027
  this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
@@ -3638,7 +3035,6 @@ export class Matterbridge extends EventEmitter {
3638
3035
  this.wssSendRefreshRequired();
3639
3036
  return;
3640
3037
  }
3641
- // Handle the command enableplugin from Home
3642
3038
  if (command === 'enableplugin') {
3643
3039
  if (!this.plugins.has(param)) {
3644
3040
  this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
@@ -3656,14 +3052,13 @@ export class Matterbridge extends EventEmitter {
3656
3052
  plugin.registeredDevices = undefined;
3657
3053
  plugin.addedDevices = undefined;
3658
3054
  await this.plugins.enable(param);
3659
- this.plugins.load(plugin, true, 'The plugin has been enabled', true); // No await do it in the background
3055
+ this.plugins.load(plugin, true, 'The plugin has been enabled', true);
3660
3056
  }
3661
3057
  }
3662
3058
  res.json({ message: 'Command received' });
3663
3059
  this.wssSendRefreshRequired();
3664
3060
  return;
3665
3061
  }
3666
- // Handle the command disableplugin from Home
3667
3062
  if (command === 'disableplugin') {
3668
3063
  if (!this.plugins.has(param)) {
3669
3064
  this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
@@ -3680,7 +3075,6 @@ export class Matterbridge extends EventEmitter {
3680
3075
  return;
3681
3076
  }
3682
3077
  });
3683
- // Fallback for routing (must be the last route)
3684
3078
  this.expressApp.get('*', (req, res) => {
3685
3079
  this.log.debug('The frontend sent:', req.url);
3686
3080
  this.log.debug('Response send file:', path.join(this.rootDirectory, 'frontend/build/index.html'));
@@ -3688,11 +3082,6 @@ export class Matterbridge extends EventEmitter {
3688
3082
  });
3689
3083
  this.log.debug(`Frontend initialized on port ${YELLOW}${port}${db} static ${UNDERLINE}${path.join(this.rootDirectory, 'frontend/build')}${UNDERLINEOFF}${rs}`);
3690
3084
  }
3691
- /**
3692
- * Retrieves the cluster text description from a given device.
3693
- * @param {MatterbridgeDevice} device - The MatterbridgeDevice object.
3694
- * @returns {string} The attributes description of the cluster servers in the device.
3695
- */
3696
3085
  getClusterTextFromDevice(device) {
3697
3086
  const stringifyUserLabel = (endpoint) => {
3698
3087
  const labelList = endpoint.getClusterServer(UserLabelCluster)?.attributes.labelList.getLocal();
@@ -3715,11 +3104,9 @@ export class Matterbridge extends EventEmitter {
3715
3104
  return '';
3716
3105
  };
3717
3106
  let attributes = '';
3718
- // this.log.debug(`***getClusterTextFromDevice: ${device.deviceName} (${device.name})`);
3719
3107
  const clusterServers = device.getAllClusterServers();
3720
3108
  clusterServers.forEach((clusterServer) => {
3721
3109
  try {
3722
- // this.log.debug(`**--clusterServer: ${clusterServer.id} (${clusterServer.name})`);
3723
3110
  if (clusterServer.name === 'OnOff')
3724
3111
  attributes += `OnOff: ${clusterServer.attributes.onOff.getLocal()} `;
3725
3112
  if (clusterServer.name === 'Switch')
@@ -3770,30 +3157,18 @@ export class Matterbridge extends EventEmitter {
3770
3157
  attributes += `${stringifyFixedLabel(device)} `;
3771
3158
  if (clusterServer.name === 'UserLabel')
3772
3159
  attributes += `${stringifyUserLabel(device)} `;
3773
- // this.log.debug(`*--clusterServer: ${clusterServer.id} (${clusterServer.name})`);
3774
3160
  }
3775
3161
  catch (error) {
3776
3162
  this.log.error(`getClusterTextFromDevice with ${clusterServer.name} error: ${error}`);
3777
3163
  }
3778
3164
  });
3779
- // this.log.debug(`*getClusterTextFromDevice: ${device.deviceName} (${device.name})`);
3780
3165
  return attributes;
3781
3166
  }
3782
- /**
3783
- * Initializes the Matterbridge instance as extension for zigbee2mqtt.
3784
- * @deprecated This method is deprecated and will be removed in a future version.
3785
- *
3786
- * @returns A Promise that resolves when the initialization is complete.
3787
- */
3788
3167
  async startExtension(dataPath, extensionVersion, port = 5540) {
3789
- // Set the bridge mode
3790
3168
  this.bridgeMode = 'bridge';
3791
- // Set the first port to use
3792
3169
  this.port = port;
3793
- // Set Matterbridge logger
3794
- this.log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: "info" /* LogLevel.INFO */ });
3170
+ this.log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4, logLevel: "info" });
3795
3171
  this.log.debug('Matterbridge extension is starting...');
3796
- // Initialize NodeStorage
3797
3172
  this.matterbridgeDirectory = dataPath;
3798
3173
  this.log.debug('Creating node storage manager dir: ' + path.join(this.matterbridgeDirectory, 'node_storage'));
3799
3174
  this.nodeStorage = new NodeStorageManager({ dir: path.join(this.matterbridgeDirectory, 'node_storage'), logging: false });
@@ -3812,13 +3187,10 @@ export class Matterbridge extends EventEmitter {
3812
3187
  };
3813
3188
  this.plugins.set(plugin);
3814
3189
  this.plugins.saveToStorage();
3815
- // Log system info and create .matterbridge directory
3816
3190
  await this.logNodeAndSystemInfo();
3817
3191
  this.matterbridgeDirectory = dataPath;
3818
- // Set matter.js logger level and format
3819
3192
  Logger.defaultLogLevel = MatterLogLevel.INFO;
3820
3193
  Logger.format = MatterLogFormat.ANSI;
3821
- // Start the storage and create matterbridgeContext
3822
3194
  await this.startMatterStorage('json', path.join(this.matterbridgeDirectory, this.matterStorageName));
3823
3195
  if (!this.storageManager)
3824
3196
  return false;
@@ -3828,7 +3200,7 @@ export class Matterbridge extends EventEmitter {
3828
3200
  await this.matterbridgeContext.set('softwareVersion', 1);
3829
3201
  await this.matterbridgeContext.set('softwareVersionString', this.matterbridgeVersion);
3830
3202
  await this.matterbridgeContext.set('hardwareVersion', 1);
3831
- await this.matterbridgeContext.set('hardwareVersionString', extensionVersion); // Update with the extension version
3203
+ await this.matterbridgeContext.set('hardwareVersionString', extensionVersion);
3832
3204
  this.matterServer = await this.createMatterServer(this.storageManager);
3833
3205
  this.log.debug(`Creating commissioning server for ${plg}Matterbridge${db}`);
3834
3206
  this.commissioningServer = await this.createCommisioningServer(this.matterbridgeContext, 'Matterbridge');
@@ -3841,7 +3213,6 @@ export class Matterbridge extends EventEmitter {
3841
3213
  await this.startMatterServer();
3842
3214
  this.log.info('Matter server started');
3843
3215
  await this.showCommissioningQRCode(this.commissioningServer, this.matterbridgeContext, this.nodeContext, 'Matterbridge');
3844
- // Set reachability to true and trigger event after 60 seconds
3845
3216
  setTimeout(() => {
3846
3217
  this.log.info(`Setting reachability to true for ${plg}Matterbridge${db}`);
3847
3218
  if (this.commissioningServer)
@@ -3851,31 +3222,14 @@ export class Matterbridge extends EventEmitter {
3851
3222
  }, 60 * 1000);
3852
3223
  return this.commissioningServer.isCommissioned();
3853
3224
  }
3854
- /**
3855
- * Close the Matterbridge instance as extension for zigbee2mqtt.
3856
- * @deprecated This method is deprecated and will be removed in a future version.
3857
- *
3858
- * @returns A Promise that resolves when the initialization is complete.
3859
- */
3860
3225
  async stopExtension() {
3861
- // Closing matter
3862
3226
  await this.stopMatterServer();
3863
- // Clearing the session manager
3864
- // this.matterbridgeContext?.createContext('SessionManager').clear();
3865
- // Closing storage
3866
3227
  await this.stopMatterStorage();
3867
3228
  this.log.info('Matter server stopped');
3868
3229
  }
3869
- /**
3870
- * Checks if the extension is commissioned.
3871
- * @deprecated This method is deprecated and will be removed in a future version.
3872
- *
3873
- * @returns {boolean} Returns true if the extension is commissioned, false otherwise.
3874
- */
3875
3230
  isExtensionCommissioned() {
3876
3231
  if (!this.commissioningServer)
3877
3232
  return false;
3878
3233
  return this.commissioningServer.isCommissioned();
3879
3234
  }
3880
3235
  }
3881
- //# sourceMappingURL=matterbridge.js.map