matterbridge 1.6.8-dev.2 → 1.6.8-dev.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/CHANGELOG.md +23 -4
  2. package/README-DOCKER.md +8 -6
  3. package/README-EDGE.md +76 -0
  4. package/README-SERVICE.md +3 -3
  5. package/README.md +7 -4
  6. package/dist/cli.js +0 -26
  7. package/dist/cluster/export.js +0 -2
  8. package/dist/defaultConfigSchema.js +3 -24
  9. package/dist/deviceManager.js +1 -26
  10. package/dist/index.js +0 -30
  11. package/dist/logger/export.js +0 -1
  12. package/dist/matter/export.js +0 -1
  13. package/dist/matterbridge.js +315 -678
  14. package/dist/matterbridgeAccessoryPlatform.js +0 -33
  15. package/dist/matterbridgeBehaviors.js +1 -29
  16. package/dist/matterbridgeDevice.js +9 -995
  17. package/dist/matterbridgeDeviceTypes.js +11 -82
  18. package/dist/matterbridgeDynamicPlatform.js +0 -33
  19. package/dist/matterbridgeEdge.js +2 -531
  20. package/dist/matterbridgeEndpoint.js +11 -1120
  21. package/dist/matterbridgePlatform.js +69 -95
  22. package/dist/matterbridgeTypes.js +0 -24
  23. package/dist/matterbridgeWebsocket.js +0 -45
  24. package/dist/pluginManager.js +3 -238
  25. package/dist/storage/export.js +0 -1
  26. package/dist/utils/colorUtils.js +2 -205
  27. package/dist/utils/export.js +0 -1
  28. package/dist/utils/utils.js +7 -252
  29. package/frontend/build/asset-manifest.json +6 -6
  30. package/frontend/build/index.html +1 -1
  31. package/frontend/build/static/css/{main.823e08b6.css → main.fa9c13f2.css} +2 -2
  32. package/frontend/build/static/css/main.fa9c13f2.css.map +1 -0
  33. package/frontend/build/static/js/{main.4dd7e165.js → main.f1f06641.js} +15 -15
  34. package/frontend/build/static/js/main.f1f06641.js.map +1 -0
  35. package/npm-shrinkwrap.json +12 -12
  36. package/package.json +1 -1
  37. package/dist/cli.d.ts.map +0 -1
  38. package/dist/cli.js.map +0 -1
  39. package/dist/cluster/export.d.ts.map +0 -1
  40. package/dist/cluster/export.js.map +0 -1
  41. package/dist/defaultConfigSchema.d.ts.map +0 -1
  42. package/dist/defaultConfigSchema.js.map +0 -1
  43. package/dist/deviceManager.d.ts +0 -46
  44. package/dist/deviceManager.d.ts.map +0 -1
  45. package/dist/deviceManager.js.map +0 -1
  46. package/dist/index.d.ts.map +0 -1
  47. package/dist/index.js.map +0 -1
  48. package/dist/logger/export.d.ts.map +0 -1
  49. package/dist/logger/export.js.map +0 -1
  50. package/dist/matter/export.d.ts.map +0 -1
  51. package/dist/matter/export.js.map +0 -1
  52. package/dist/matterbridge.d.ts +0 -466
  53. package/dist/matterbridge.d.ts.map +0 -1
  54. package/dist/matterbridge.js.map +0 -1
  55. package/dist/matterbridgeAccessoryPlatform.d.ts.map +0 -1
  56. package/dist/matterbridgeAccessoryPlatform.js.map +0 -1
  57. package/dist/matterbridgeBehaviors.d.ts +0 -116
  58. package/dist/matterbridgeBehaviors.d.ts.map +0 -1
  59. package/dist/matterbridgeBehaviors.js.map +0 -1
  60. package/dist/matterbridgeDevice.d.ts +0 -1142
  61. package/dist/matterbridgeDevice.d.ts.map +0 -1
  62. package/dist/matterbridgeDevice.js.map +0 -1
  63. package/dist/matterbridgeDeviceTypes.d.ts +0 -109
  64. package/dist/matterbridgeDeviceTypes.d.ts.map +0 -1
  65. package/dist/matterbridgeDeviceTypes.js.map +0 -1
  66. package/dist/matterbridgeDynamicPlatform.d.ts.map +0 -1
  67. package/dist/matterbridgeDynamicPlatform.js.map +0 -1
  68. package/dist/matterbridgeEdge.d.ts +0 -90
  69. package/dist/matterbridgeEdge.d.ts.map +0 -1
  70. package/dist/matterbridgeEdge.js.map +0 -1
  71. package/dist/matterbridgeEndpoint.d.ts +0 -1134
  72. package/dist/matterbridgeEndpoint.d.ts.map +0 -1
  73. package/dist/matterbridgeEndpoint.js.map +0 -1
  74. package/dist/matterbridgePlatform.d.ts +0 -114
  75. package/dist/matterbridgePlatform.d.ts.map +0 -1
  76. package/dist/matterbridgePlatform.js.map +0 -1
  77. package/dist/matterbridgeTypes.d.ts.map +0 -1
  78. package/dist/matterbridgeTypes.js.map +0 -1
  79. package/dist/matterbridgeWebsocket.d.ts.map +0 -1
  80. package/dist/matterbridgeWebsocket.js.map +0 -1
  81. package/dist/pluginManager.d.ts +0 -238
  82. package/dist/pluginManager.d.ts.map +0 -1
  83. package/dist/pluginManager.js.map +0 -1
  84. package/dist/storage/export.d.ts.map +0 -1
  85. package/dist/storage/export.js.map +0 -1
  86. package/dist/utils/colorUtils.d.ts.map +0 -1
  87. package/dist/utils/colorUtils.js.map +0 -1
  88. package/dist/utils/export.d.ts.map +0 -1
  89. package/dist/utils/export.js.map +0 -1
  90. package/dist/utils/utils.d.ts +0 -221
  91. package/dist/utils/utils.d.ts.map +0 -1
  92. package/dist/utils/utils.js.map +0 -1
  93. package/frontend/build/static/css/main.823e08b6.css.map +0 -1
  94. package/frontend/build/static/js/main.4dd7e165.js.map +0 -1
  95. /package/frontend/build/static/js/{main.4dd7e165.js.LICENSE.txt → main.f1f06641.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
- import { DeviceTypeId, Logger, LogLevel as MatterLogLevel, LogFormat as MatterLogFormat, VendorId, StorageManager, EndpointServer } from '@matter/main';
20
+ import { DeviceTypeId, Logger, LogLevel as MatterLogLevel, LogFormat as MatterLogFormat, VendorId, StorageManager, EndpointServer, StorageService, Environment } from '@matter/main';
48
21
  import { BasicInformationCluster, BridgedDeviceBasicInformation, BridgedDeviceBasicInformationCluster, FixedLabelCluster, GeneralCommissioning, PowerSourceCluster, SwitchCluster, ThreadNetworkDiagnosticsCluster, UserLabelCluster, } from '@matter/main/clusters';
49
22
  import { getClusterNameById, ManualPairingCodeCodec, QrCodeSchema } from '@matter/main/types';
50
23
  import { StorageBackendDisk, StorageBackendJsonFile } from '@matter/nodejs';
51
- // @project-chip
52
24
  import { CommissioningController, CommissioningServer, MatterServer } from '@project-chip/matter.js';
53
25
  import { Aggregator, DeviceTypes, NodeStateInformation } from '@project-chip/matter.js/device';
54
26
  import { aggregator } from './matterbridgeDeviceTypes.js';
55
- // Default colors
56
27
  const plg = '\u001B[38;5;33m';
57
28
  const dev = '\u001B[38;5;79m';
58
29
  const typ = '\u001B[38;5;207m';
59
- /**
60
- * Represents the Matterbridge application.
61
- */
62
30
  export class Matterbridge extends EventEmitter {
63
31
  systemInformation = {
64
32
  interfaceName: '',
@@ -95,7 +63,7 @@ export class Matterbridge extends EventEmitter {
95
63
  edge: hasParameter('edge'),
96
64
  readOnly: hasParameter('readonly'),
97
65
  profile: getParameter('profile'),
98
- loggerLevel: "info" /* LogLevel.INFO */,
66
+ loggerLevel: "info",
99
67
  fileLogger: false,
100
68
  matterLoggerLevel: MatterLogLevel.INFO,
101
69
  matterFileLogger: false,
@@ -134,7 +102,6 @@ export class Matterbridge extends EventEmitter {
134
102
  nodeContext;
135
103
  matterStorageName = 'matterbridge' + (getParameter('profile') ? '.' + getParameter('profile') : '') + '.json';
136
104
  nodeStorageName = 'storage' + (getParameter('profile') ? '.' + getParameter('profile') : '');
137
- // Cleanup
138
105
  hasCleanupStarted = false;
139
106
  initialized = false;
140
107
  execRunningCount = 0;
@@ -146,18 +113,16 @@ export class Matterbridge extends EventEmitter {
146
113
  sigtermHandler;
147
114
  exceptionHandler;
148
115
  rejectionHandler;
149
- // Frontend
150
116
  expressApp;
151
117
  httpServer;
152
118
  httpsServer;
153
119
  webSocketServer;
154
- // Matter
155
- mdnsInterface; // matter server mdnsInterface: e.g. 'eth0' or 'wlan0' or 'WiFi'
156
- ipv4address; // matter commissioning server listeningAddressIpv4
157
- ipv6address; // matter commissioning server listeningAddressIpv6
158
- port = 5540; // first commissioning server port
159
- passcode; // first commissioning server passcode
160
- discriminator; // first commissioning server discriminator
120
+ mdnsInterface;
121
+ ipv4address;
122
+ ipv6address;
123
+ port = 5540;
124
+ passcode;
125
+ discriminator;
161
126
  storageManager;
162
127
  matterbridgeContext;
163
128
  mattercontrollerContext;
@@ -168,26 +133,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
  }
140
+ getDevices() {
141
+ return this.devices.array();
142
+ }
143
+ getPlugins() {
144
+ return this.plugins.array();
145
+ }
177
146
  matterbridgeMessageHandler;
178
- /** ***********************************************************************************************************************************/
179
- /** loadInstance() and cleanup() methods */
180
- /** ***********************************************************************************************************************************/
181
- /**
182
- * Loads an instance of the Matterbridge class.
183
- * If an instance already exists, return that instance.
184
- *
185
- * @param initialize - Whether to initialize the Matterbridge instance after loading.
186
- * @returns The loaded Matterbridge instance.
187
- */
188
147
  static async loadInstance(initialize = false) {
189
148
  if (!Matterbridge.instance) {
190
- // eslint-disable-next-line no-console
191
149
  if (hasParameter('debug'))
192
150
  console.log(GREEN + 'Creating a new instance of Matterbridge.', initialize ? 'Initializing...' : 'Not initializing...', rs);
193
151
  Matterbridge.instance = new Matterbridge();
@@ -196,11 +154,6 @@ export class Matterbridge extends EventEmitter {
196
154
  }
197
155
  return Matterbridge.instance;
198
156
  }
199
- /**
200
- * Call cleanup().
201
- * @deprecated This method is deprecated and is only used for jest tests.
202
- *
203
- */
204
157
  async destroyInstance() {
205
158
  await this.cleanup('destroying instance...', false);
206
159
  await waiter('destroying instance...', () => {
@@ -208,60 +161,39 @@ export class Matterbridge extends EventEmitter {
208
161
  }, false, 60000, 100, false);
209
162
  await wait(1000, 'Wait for the global node_modules and matterbridge version', false);
210
163
  }
211
- /**
212
- * Initializes the Matterbridge application.
213
- *
214
- * @remarks
215
- * This method performs the necessary setup and initialization steps for the Matterbridge application.
216
- * It displays the help information if the 'help' parameter is provided, sets up the logger, checks the
217
- * node version, registers signal handlers, initializes storage, and parses the command line.
218
- *
219
- * @returns A Promise that resolves when the initialization is complete.
220
- */
221
164
  async initialize() {
222
- // Set the restart mode
223
165
  if (hasParameter('service'))
224
166
  this.restartMode = 'service';
225
167
  if (hasParameter('docker'))
226
168
  this.restartMode = 'docker';
227
- // Set the matterbridge directory
228
169
  this.homeDirectory = getParameter('homedir') ?? os.homedir();
229
170
  this.matterbridgeDirectory = path.join(this.homeDirectory, '.matterbridge');
230
- // Create matterbridge logger
231
- this.log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: hasParameter('debug') ? "debug" /* LogLevel.DEBUG */ : "info" /* LogLevel.INFO */ });
232
- // Initialize nodeStorage and nodeContext
171
+ this.log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4, logLevel: hasParameter('debug') ? "debug" : "info" });
233
172
  try {
234
173
  this.log.debug(`Creating node storage manager: ${CYAN}${this.nodeStorageName}${db}`);
235
174
  this.nodeStorage = new NodeStorageManager({ dir: path.join(this.matterbridgeDirectory, this.nodeStorageName), writeQueue: false, expiredInterval: undefined, logging: false });
236
175
  this.log.debug('Creating node storage context for matterbridge');
237
176
  this.nodeContext = await this.nodeStorage.createStorage('matterbridge');
238
- // TODO: Remove this code when node-persist-manager is updated
239
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
240
177
  const keys = (await this.nodeStorage?.storage.keys());
241
178
  for (const key of keys) {
242
179
  this.log.debug(`Checking node storage manager key: ${CYAN}${key}${db}`);
243
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
244
180
  await this.nodeStorage?.storage.get(key);
245
181
  }
246
182
  const storages = await this.nodeStorage.getStorageNames();
247
183
  for (const storage of storages) {
248
184
  this.log.debug(`Checking storage: ${CYAN}${storage}${db}`);
249
185
  const nodeContext = await this.nodeStorage?.createStorage(storage);
250
- // TODO: Remove this code when node-persist-manager is updated
251
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
252
186
  const keys = (await nodeContext?.storage.keys());
253
187
  keys.forEach(async (key) => {
254
188
  this.log.debug(`Checking key: ${CYAN}${storage}:${key}${db}`);
255
189
  await nodeContext?.get(key);
256
190
  });
257
191
  }
258
- // Creating a backup of the node storage since it is not corrupted
259
192
  this.log.debug('Creating node storage backup...');
260
193
  await copyDirectory(path.join(this.matterbridgeDirectory, this.nodeStorageName), path.join(this.matterbridgeDirectory, this.nodeStorageName + '.backup'));
261
194
  this.log.debug('Created node storage backup');
262
195
  }
263
196
  catch (error) {
264
- // Restoring the backup of the node storage since it is corrupted
265
197
  this.log.error(`Error creating node storage manager and context: ${error instanceof Error ? error.message : error}`);
266
198
  if (hasParameter('norestore')) {
267
199
  this.log.fatal(`The matterbridge node storage is corrupted. Parameter -norestore found: exiting...`);
@@ -276,51 +208,45 @@ export class Matterbridge extends EventEmitter {
276
208
  this.log.fatal('Fatal error creating node storage manager and context for matterbridge');
277
209
  throw new Error('Fatal error creating node storage manager and context for matterbridge');
278
210
  }
279
- // Set the first port to use for the commissioning server (will be incremented in childbridge mode)
280
211
  this.port = getIntParameter('port') ?? (await this.nodeContext.get('matterport', 5540)) ?? 5540;
281
- // Set the first passcode to use for the commissioning server (will be incremented in childbridge mode)
282
212
  this.passcode = this.passcode ?? getIntParameter('passcode') ?? (await this.nodeContext.get('matterpasscode'));
283
- // Set the first discriminator to use for the commissioning server (will be incremented in childbridge mode)
284
213
  this.discriminator = this.discriminator ?? getIntParameter('discriminator') ?? (await this.nodeContext.get('matterdiscriminator'));
285
214
  this.log.debug(`Initializing commissioning server for Matterbridge... on port ${this.port} with passcode ${this.passcode} and discriminator ${this.discriminator}`);
286
- // Set matterbridge logger level (context: matterbridgeLogLevel)
287
215
  if (hasParameter('logger')) {
288
216
  const level = getParameter('logger');
289
217
  if (level === 'debug') {
290
- this.log.logLevel = "debug" /* LogLevel.DEBUG */;
218
+ this.log.logLevel = "debug";
291
219
  }
292
220
  else if (level === 'info') {
293
- this.log.logLevel = "info" /* LogLevel.INFO */;
221
+ this.log.logLevel = "info";
294
222
  }
295
223
  else if (level === 'notice') {
296
- this.log.logLevel = "notice" /* LogLevel.NOTICE */;
224
+ this.log.logLevel = "notice";
297
225
  }
298
226
  else if (level === 'warn') {
299
- this.log.logLevel = "warn" /* LogLevel.WARN */;
227
+ this.log.logLevel = "warn";
300
228
  }
301
229
  else if (level === 'error') {
302
- this.log.logLevel = "error" /* LogLevel.ERROR */;
230
+ this.log.logLevel = "error";
303
231
  }
304
232
  else if (level === 'fatal') {
305
- this.log.logLevel = "fatal" /* LogLevel.FATAL */;
233
+ this.log.logLevel = "fatal";
306
234
  }
307
235
  else {
308
236
  this.log.warn(`Invalid matterbridge logger level: ${level}. Using default level "info".`);
309
- this.log.logLevel = "info" /* LogLevel.INFO */;
237
+ this.log.logLevel = "info";
310
238
  }
311
239
  }
312
240
  else {
313
- this.log.logLevel = await this.nodeContext.get('matterbridgeLogLevel', "info" /* LogLevel.INFO */);
241
+ this.log.logLevel = await this.nodeContext.get('matterbridgeLogLevel', "info");
314
242
  }
315
243
  MatterbridgeDevice.logLevel = this.log.logLevel;
316
- // Create the file logger for matterbridge (context: matterbridgeFileLog)
317
244
  if (hasParameter('filelogger') || (await this.nodeContext.get('matterbridgeFileLog', false))) {
318
245
  AnsiLogger.setGlobalLogfile(path.join(this.matterbridgeDirectory, this.matterbrideLoggerFile), this.log.logLevel, true);
319
246
  this.matterbridgeInformation.fileLogger = true;
320
247
  }
321
248
  this.log.notice('Matterbridge is starting...');
322
249
  this.log.debug(`Matterbridge logLevel: ${this.log.logLevel} fileLoger: ${this.matterbridgeInformation.fileLogger}.`);
323
- // Set matter.js logger level, format and logger (context: matterLogLevel)
324
250
  if (hasParameter('matterlogger')) {
325
251
  const level = getParameter('matterlogger');
326
252
  if (level === 'debug') {
@@ -351,7 +277,6 @@ export class Matterbridge extends EventEmitter {
351
277
  }
352
278
  Logger.format = MatterLogFormat.ANSI;
353
279
  Logger.setLogger('default', this.createMatterLogger());
354
- // Create the file logger for matter.js (context: matterFileLog)
355
280
  if (hasParameter('matterfilelogger') || (await this.nodeContext.get('matterFileLog', false))) {
356
281
  this.matterbridgeInformation.matterFileLogger = true;
357
282
  Logger.addLogger('matterfilelogger', await this.createMatterFileLogger(path.join(this.matterbridgeDirectory, this.matterLoggerFile), true), {
@@ -360,7 +285,6 @@ export class Matterbridge extends EventEmitter {
360
285
  });
361
286
  }
362
287
  this.log.debug(`Matter logLevel: ${Logger.defaultLogLevel} fileLoger: ${this.matterbridgeInformation.matterFileLogger}.`);
363
- // Set the interface to use for the matter server mdnsInterface
364
288
  if (hasParameter('mdnsinterface')) {
365
289
  this.mdnsInterface = getParameter('mdnsinterface');
366
290
  }
@@ -369,7 +293,6 @@ export class Matterbridge extends EventEmitter {
369
293
  if (this.mdnsInterface === '')
370
294
  this.mdnsInterface = undefined;
371
295
  }
372
- // Set the listeningAddressIpv4 for the matter commissioning server
373
296
  if (hasParameter('ipv4address')) {
374
297
  this.ipv4address = getParameter('ipv4address');
375
298
  }
@@ -378,7 +301,6 @@ export class Matterbridge extends EventEmitter {
378
301
  if (this.ipv4address === '')
379
302
  this.ipv4address = undefined;
380
303
  }
381
- // Set the listeningAddressIpv6 for the matter commissioning server
382
304
  if (hasParameter('ipv6address')) {
383
305
  this.ipv6address = getParameter('ipv6address');
384
306
  }
@@ -387,23 +309,17 @@ export class Matterbridge extends EventEmitter {
387
309
  if (this.ipv6address === '')
388
310
  this.ipv6address = undefined;
389
311
  }
390
- // Initialize PluginManager
391
312
  this.plugins = new PluginManager(this);
392
313
  await this.plugins.loadFromStorage();
393
- // Initialize DeviceManager
394
314
  this.devices = new DeviceManager(this, this.nodeContext);
395
- // Get the plugins from node storage and create the plugins node storage contexts
396
315
  for (const plugin of this.plugins) {
397
316
  const packageJson = await this.plugins.parse(plugin);
398
317
  if (packageJson === null && !hasParameter('add')) {
399
- // Try to reinstall the plugin from npm (for Docker pull and external plugins)
400
- // We don't do this when the add parameter is set because we shut down the process after adding the plugin
401
318
  this.log.info(`Error parsing plugin ${plg}${plugin.name}${nf}. Trying to reinstall it from npm.`);
402
319
  try {
403
320
  await this.spawnCommand('npm', ['install', '-g', plugin.name, '--omit=dev', '--verbose']);
404
321
  this.log.info(`Plugin ${plg}${plugin.name}${nf} reinstalled.`);
405
322
  plugin.error = false;
406
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
407
323
  }
408
324
  catch (error) {
409
325
  plugin.error = true;
@@ -420,7 +336,6 @@ export class Matterbridge extends EventEmitter {
420
336
  await plugin.nodeContext.set('description', plugin.description);
421
337
  await plugin.nodeContext.set('author', plugin.author);
422
338
  }
423
- // Log system info and create .matterbridge directory
424
339
  await this.logNodeAndSystemInfo();
425
340
  this.log.notice(`Matterbridge version ${this.matterbridgeVersion} ` +
426
341
  `${hasParameter('bridge') || (!hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'bridge') ? 'mode bridge ' : ''}` +
@@ -428,7 +343,6 @@ export class Matterbridge extends EventEmitter {
428
343
  `${hasParameter('controller') ? 'mode controller ' : ''}` +
429
344
  `${this.restartMode !== '' ? 'restart mode ' + this.restartMode + ' ' : ''}` +
430
345
  `running on ${this.systemInformation.osType} (v.${this.systemInformation.osRelease}) platform ${this.systemInformation.osPlatform} arch ${this.systemInformation.osArch}`);
431
- // Check node version and throw error
432
346
  const minNodeVersion = 18;
433
347
  const nodeVersion = process.versions.node;
434
348
  const versionMajor = parseInt(nodeVersion.split('.')[0]);
@@ -436,17 +350,10 @@ export class Matterbridge extends EventEmitter {
436
350
  this.log.error(`Node version ${versionMajor} is not supported. Please upgrade to ${minNodeVersion} or above.`);
437
351
  throw new Error(`Node version ${versionMajor} is not supported. Please upgrade to ${minNodeVersion} or above.`);
438
352
  }
439
- // Register process handlers
440
353
  this.registerProcessHandlers();
441
- // Parse command line
442
354
  await this.parseCommandLine();
443
355
  this.initialized = true;
444
356
  }
445
- /**
446
- * Parses the command line arguments and performs the corresponding actions.
447
- * @private
448
- * @returns {Promise<void>} A promise that resolves when the command line arguments have been processed, or the process exits.
449
- */
450
357
  async parseCommandLine() {
451
358
  if (hasParameter('help')) {
452
359
  this.log.info(`\nUsage: matterbridge [options]\n
@@ -554,20 +461,36 @@ export class Matterbridge extends EventEmitter {
554
461
  }
555
462
  if (hasParameter('factoryreset')) {
556
463
  try {
557
- // Delete matter storage file
558
- await fs.unlink(path.join(this.matterbridgeDirectory, this.matterStorageName));
464
+ const file = path.join(this.matterbridgeDirectory, 'matterbridge' + (getParameter('profile') ? '.' + getParameter('profile') : '') + '.json');
465
+ this.log.info(`Unlinking old matter storage file: ${file}`);
466
+ await fs.unlink(file);
559
467
  }
560
468
  catch (err) {
561
- this.log.error(`Error deleting storage: ${err}`);
469
+ if (err instanceof Error && err.code !== 'ENOENT') {
470
+ this.log.error(`Error unlinking old matter storage file: ${err}`);
471
+ }
562
472
  }
563
473
  try {
564
- // Delete node storage directory with its subdirectories
565
- await fs.rm(path.join(this.matterbridgeDirectory, this.nodeStorageName), { recursive: true });
474
+ const dir = path.join(this.matterbridgeDirectory, 'matterstorage' + (getParameter('profile') ? '.' + getParameter('profile') : ''));
475
+ this.log.info(`Removing matter node storage directory: ${dir}`);
476
+ await fs.rm(dir, { recursive: true });
566
477
  }
567
478
  catch (err) {
568
- this.log.error(`Error removing storage directory: ${err}`);
479
+ if (err instanceof Error && err.code !== 'ENOENT') {
480
+ this.log.error(`Error removing matter storage directory: ${err}`);
481
+ }
569
482
  }
570
- this.log.info('Factory reset done! Remove all paired devices from the controllers.');
483
+ try {
484
+ const dir = path.join(this.matterbridgeDirectory, 'storage' + (getParameter('profile') ? '.' + getParameter('profile') : ''));
485
+ this.log.info(`Removing storage directory: ${dir}`);
486
+ await fs.rm(dir, { recursive: true });
487
+ }
488
+ catch (err) {
489
+ if (err instanceof Error && err.code !== 'ENOENT') {
490
+ this.log.error(`Error removing storage directory: ${err}`);
491
+ }
492
+ }
493
+ this.log.info('Factory reset done! Remove all paired fabrics from the controllers.');
571
494
  this.nodeContext = undefined;
572
495
  this.nodeStorage = undefined;
573
496
  this.plugins.clear();
@@ -575,7 +498,6 @@ export class Matterbridge extends EventEmitter {
575
498
  this.emit('shutdown');
576
499
  return;
577
500
  }
578
- // Start the matter storage and create the matterbridge context
579
501
  try {
580
502
  await this.startMatterStorage('json', path.join(this.matterbridgeDirectory, this.matterStorageName));
581
503
  }
@@ -583,7 +505,7 @@ export class Matterbridge extends EventEmitter {
583
505
  this.log.fatal(`Fatal error creating matter storage: ${error instanceof Error ? error.message : error}`);
584
506
  throw new Error(`Fatal error creating matter storage: ${error instanceof Error ? error.message : error}`);
585
507
  }
586
- if (hasParameter('reset') && getParameter('reset') === undefined) {
508
+ if (!this.edge && hasParameter('reset') && getParameter('reset') === undefined) {
587
509
  this.log.info('Resetting Matterbridge commissioning information...');
588
510
  await this.matterbridgeContext?.clearAll();
589
511
  await this.stopMatterStorage();
@@ -591,7 +513,7 @@ export class Matterbridge extends EventEmitter {
591
513
  this.emit('shutdown');
592
514
  return;
593
515
  }
594
- if (getParameter('reset') && getParameter('reset') !== undefined) {
516
+ if (!this.edge && hasParameter('reset') && getParameter('reset') !== undefined) {
595
517
  this.log.debug(`Reset plugin ${getParameter('reset')}`);
596
518
  const plugin = this.plugins.get(getParameter('reset'));
597
519
  if (plugin) {
@@ -610,34 +532,28 @@ export class Matterbridge extends EventEmitter {
610
532
  this.emit('shutdown');
611
533
  return;
612
534
  }
613
- // Initialize frontend
614
535
  if (getIntParameter('frontend') !== 0 || getIntParameter('frontend') === undefined)
615
536
  await this.initializeFrontend(getIntParameter('frontend'));
616
- // Check each 60 minutes the latest versions
617
537
  this.checkUpdateInterval = setInterval(() => {
618
538
  this.getMatterbridgeLatestVersion();
619
539
  for (const plugin of this.plugins) {
620
540
  this.getPluginLatestVersion(plugin);
621
541
  }
622
542
  }, 60 * 60 * 1000);
623
- // Start the matterbridge in mode test
624
543
  if (hasParameter('test')) {
625
544
  this.bridgeMode = 'bridge';
626
545
  MatterbridgeDevice.bridgeMode = 'bridge';
627
546
  return;
628
547
  }
629
- // Start the matterbridge in mode controller
630
548
  if (hasParameter('controller')) {
631
549
  this.bridgeMode = 'controller';
632
550
  await this.startController();
633
551
  return;
634
552
  }
635
- // Check if the bridge mode is set and start matterbridge in bridge mode if not set
636
553
  if (!hasParameter('bridge') && !hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === '') {
637
554
  this.log.info('Setting default matterbridge start mode to bridge');
638
555
  await this.nodeContext?.set('bridgeMode', 'bridge');
639
556
  }
640
- // Start matterbridge in bridge mode
641
557
  if (hasParameter('bridge') || (!hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'bridge')) {
642
558
  this.bridgeMode = 'bridge';
643
559
  MatterbridgeDevice.bridgeMode = 'bridge';
@@ -646,7 +562,6 @@ export class Matterbridge extends EventEmitter {
646
562
  await this.startBridge();
647
563
  return;
648
564
  }
649
- // Start matterbridge in childbridge mode
650
565
  if (hasParameter('childbridge') || (!hasParameter('bridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'childbridge')) {
651
566
  this.bridgeMode = 'childbridge';
652
567
  MatterbridgeDevice.bridgeMode = 'childbridge';
@@ -656,28 +571,17 @@ export class Matterbridge extends EventEmitter {
656
571
  return;
657
572
  }
658
573
  }
659
- /**
660
- * Asynchronously loads and starts the registered plugins.
661
- *
662
- * This method is responsible for initializing and staarting all enabled plugins.
663
- * It ensures that each plugin is properly loaded and started before the ridge starts.
664
- *
665
- * @returns {Promise<void>} A promise that resolves when all plugins have been loaded and started.
666
- */
667
574
  async startPlugins() {
668
- // Check, load and start the plugins
669
575
  for (const plugin of this.plugins) {
670
576
  plugin.configJson = await this.plugins.loadConfig(plugin);
671
577
  plugin.schemaJson = await this.plugins.loadSchema(plugin);
672
- // Check if the plugin is available
673
578
  if (!(await this.plugins.resolve(plugin.path))) {
674
579
  this.log.error(`Plugin ${plg}${plugin.name}${er} not found or not validated. Disabling it.`);
675
580
  plugin.enabled = false;
676
581
  plugin.error = true;
677
582
  continue;
678
583
  }
679
- // Check if the plugin has a new version
680
- this.getPluginLatestVersion(plugin); // No await do it asyncronously
584
+ this.getPluginLatestVersion(plugin);
681
585
  if (!plugin.enabled) {
682
586
  this.log.info(`Plugin ${plg}${plugin.name}${nf} not enabled`);
683
587
  continue;
@@ -692,26 +596,20 @@ export class Matterbridge extends EventEmitter {
692
596
  plugin.addedDevices = undefined;
693
597
  plugin.qrPairingCode = undefined;
694
598
  plugin.manualPairingCode = undefined;
695
- this.plugins.load(plugin, true, 'Matterbridge is starting'); // No await do it asyncronously
599
+ this.plugins.load(plugin, true, 'Matterbridge is starting');
696
600
  }
697
601
  this.wssSendRefreshRequired();
698
602
  }
699
- /**
700
- * Registers the process handlers for uncaughtException, unhandledRejection, SIGINT and SIGTERM.
701
- * When either of these signals are received, the cleanup method is called with an appropriate message.
702
- */
703
603
  registerProcessHandlers() {
704
604
  this.log.debug(`Registering uncaughtException and unhandledRejection handlers...`);
705
605
  process.removeAllListeners('uncaughtException');
706
606
  process.removeAllListeners('unhandledRejection');
707
607
  this.exceptionHandler = async (error) => {
708
608
  this.log.fatal('Unhandled Exception detected at:', error.stack || error, rs);
709
- // await this.cleanup('Unhandled Exception detected, cleaning up...');
710
609
  };
711
610
  process.on('uncaughtException', this.exceptionHandler);
712
611
  this.rejectionHandler = async (reason, promise) => {
713
612
  this.log.fatal('Unhandled Rejection detected at:', promise, 'reason:', reason instanceof Error ? reason.stack : reason, rs);
714
- // await this.cleanup('Unhandled Rejection detected, cleaning up...');
715
613
  };
716
614
  process.on('unhandledRejection', this.rejectionHandler);
717
615
  this.log.debug(`Registering SIGINT and SIGTERM signal handlers...`);
@@ -724,9 +622,6 @@ export class Matterbridge extends EventEmitter {
724
622
  };
725
623
  process.on('SIGTERM', this.sigtermHandler);
726
624
  }
727
- /**
728
- * Deregisters the process uncaughtException, unhandledRejection, SIGINT and SIGTERM signal handlers.
729
- */
730
625
  deregisterProcesslHandlers() {
731
626
  this.log.debug(`Deregistering uncaughtException and unhandledRejection handlers...`);
732
627
  if (this.exceptionHandler)
@@ -743,11 +638,7 @@ export class Matterbridge extends EventEmitter {
743
638
  process.off('SIGTERM', this.sigtermHandler);
744
639
  this.sigtermHandler = undefined;
745
640
  }
746
- /**
747
- * Logs the node and system information.
748
- */
749
641
  async logNodeAndSystemInfo() {
750
- // IP address information
751
642
  const networkInterfaces = os.networkInterfaces();
752
643
  this.systemInformation.ipv4Address = '';
753
644
  this.systemInformation.ipv6Address = '';
@@ -767,7 +658,7 @@ export class Matterbridge extends EventEmitter {
767
658
  this.systemInformation.macAddress = detail.mac;
768
659
  }
769
660
  }
770
- if (this.systemInformation.ipv4Address !== '' /* && this.systemInformation.ipv6Address !== ''*/) {
661
+ if (this.systemInformation.ipv4Address !== '') {
771
662
  this.log.debug(`Using interface: '${this.systemInformation.interfaceName}'`);
772
663
  this.log.debug(`- with MAC address: '${this.systemInformation.macAddress}'`);
773
664
  this.log.debug(`- with IPv4 address: '${this.systemInformation.ipv4Address}'`);
@@ -775,22 +666,19 @@ export class Matterbridge extends EventEmitter {
775
666
  break;
776
667
  }
777
668
  }
778
- // Node information
779
669
  this.systemInformation.nodeVersion = process.versions.node;
780
670
  const versionMajor = parseInt(this.systemInformation.nodeVersion.split('.')[0]);
781
671
  const versionMinor = parseInt(this.systemInformation.nodeVersion.split('.')[1]);
782
672
  const versionPatch = parseInt(this.systemInformation.nodeVersion.split('.')[2]);
783
- // Host system information
784
673
  this.systemInformation.hostname = os.hostname();
785
674
  this.systemInformation.user = os.userInfo().username;
786
- this.systemInformation.osType = os.type(); // "Windows_NT", "Darwin", etc.
787
- this.systemInformation.osRelease = os.release(); // Kernel version
788
- this.systemInformation.osPlatform = os.platform(); // "win32", "linux", "darwin", etc.
789
- this.systemInformation.osArch = os.arch(); // "x64", "arm", etc.
790
- this.systemInformation.totalMemory = (os.totalmem() / 1024 / 1024 / 1024).toFixed(2) + ' GB'; // Convert to GB
791
- this.systemInformation.freeMemory = (os.freemem() / 1024 / 1024 / 1024).toFixed(2) + ' GB'; // Convert to GB
792
- this.systemInformation.systemUptime = (os.uptime() / 60 / 60).toFixed(2) + ' hours'; // Convert to hours
793
- // Log the system information
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';
794
682
  this.log.debug('Host System Information:');
795
683
  this.log.debug(`- Hostname: ${this.systemInformation.hostname}`);
796
684
  this.log.debug(`- User: ${this.systemInformation.user}`);
@@ -806,19 +694,15 @@ export class Matterbridge extends EventEmitter {
806
694
  this.log.debug(`- Total Memory: ${this.systemInformation.totalMemory}`);
807
695
  this.log.debug(`- Free Memory: ${this.systemInformation.freeMemory}`);
808
696
  this.log.debug(`- System Uptime: ${this.systemInformation.systemUptime}`);
809
- // Home directory
810
697
  this.homeDirectory = getParameter('homedir') ?? os.homedir();
811
698
  this.matterbridgeInformation.homeDirectory = this.homeDirectory;
812
699
  this.log.debug(`Home Directory: ${this.homeDirectory}`);
813
- // Package root directory
814
700
  const currentFileDirectory = path.dirname(fileURLToPath(import.meta.url));
815
701
  this.rootDirectory = path.resolve(currentFileDirectory, '../');
816
702
  this.matterbridgeInformation.rootDirectory = this.rootDirectory;
817
703
  this.log.debug(`Root Directory: ${this.rootDirectory}`);
818
- // Global node_modules directory
819
704
  if (this.nodeContext)
820
705
  this.globalModulesDirectory = await this.nodeContext.get('globalModulesDirectory', '');
821
- // First run of Matterbridge so the node storage is empty
822
706
  if (this.globalModulesDirectory === '') {
823
707
  try {
824
708
  this.globalModulesDirectory = await this.getGlobalNodeModules();
@@ -842,7 +726,6 @@ export class Matterbridge extends EventEmitter {
842
726
  this.log.error(`Error getting global node_modules directory: ${error}`);
843
727
  });
844
728
  }
845
- // Create the data directory .matterbridge in the home directory
846
729
  this.matterbridgeDirectory = path.join(this.homeDirectory, '.matterbridge');
847
730
  this.matterbridgeInformation.matterbridgeDirectory = this.matterbridgeDirectory;
848
731
  try {
@@ -866,7 +749,6 @@ export class Matterbridge extends EventEmitter {
866
749
  }
867
750
  }
868
751
  this.log.debug(`Matterbridge Directory: ${this.matterbridgeDirectory}`);
869
- // Create the plugin directory Matterbridge in the home directory
870
752
  this.matterbridgePluginDirectory = path.join(this.homeDirectory, 'Matterbridge');
871
753
  this.matterbridgeInformation.matterbridgePluginDirectory = this.matterbridgePluginDirectory;
872
754
  try {
@@ -890,28 +772,19 @@ export class Matterbridge extends EventEmitter {
890
772
  }
891
773
  }
892
774
  this.log.debug(`Matterbridge Plugin Directory: ${this.matterbridgePluginDirectory}`);
893
- // Matterbridge version
894
775
  const packageJson = JSON.parse(await fs.readFile(path.join(this.rootDirectory, 'package.json'), 'utf-8'));
895
776
  this.matterbridgeVersion = packageJson.version;
896
777
  this.matterbridgeInformation.matterbridgeVersion = this.matterbridgeVersion;
897
778
  this.log.debug(`Matterbridge Version: ${this.matterbridgeVersion}`);
898
- // Matterbridge latest version
899
779
  if (this.nodeContext)
900
780
  this.matterbridgeLatestVersion = await this.nodeContext.get('matterbridgeLatestVersion', '');
901
781
  this.log.debug(`Matterbridge Latest Version: ${this.matterbridgeLatestVersion}`);
902
782
  this.getMatterbridgeLatestVersion();
903
- // Current working directory
904
783
  const currentDir = process.cwd();
905
784
  this.log.debug(`Current Working Directory: ${currentDir}`);
906
- // Command line arguments (excluding 'node' and the script name)
907
785
  const cmdArgs = process.argv.slice(2).join(' ');
908
786
  this.log.debug(`Command Line Arguments: ${cmdArgs}`);
909
787
  }
910
- /**
911
- * Retrieves the latest version of a package from the npm registry.
912
- * @param packageName - The name of the package.
913
- * @returns A Promise that resolves to the latest version of the package.
914
- */
915
788
  async getLatestVersion(packageName) {
916
789
  return new Promise((resolve, reject) => {
917
790
  this.execRunningCount++;
@@ -926,10 +799,6 @@ export class Matterbridge extends EventEmitter {
926
799
  });
927
800
  });
928
801
  }
929
- /**
930
- * Retrieves the path to the global Node.js modules directory.
931
- * @returns A promise that resolves to the path of the global Node.js modules directory.
932
- */
933
802
  async getGlobalNodeModules() {
934
803
  return new Promise((resolve, reject) => {
935
804
  this.execRunningCount++;
@@ -944,11 +813,6 @@ export class Matterbridge extends EventEmitter {
944
813
  });
945
814
  });
946
815
  }
947
- /**
948
- * Retrieves the latest version of Matterbridge and performs necessary actions based on the version comparison.
949
- * @private
950
- * @returns {Promise<void>} A promise that resolves when the latest version is retrieved and actions are performed.
951
- */
952
816
  async getMatterbridgeLatestVersion() {
953
817
  this.getLatestVersion('matterbridge')
954
818
  .then(async (matterbridgeLatestVersion) => {
@@ -965,19 +829,8 @@ export class Matterbridge extends EventEmitter {
965
829
  })
966
830
  .catch((error) => {
967
831
  this.log.error(`Error getting Matterbridge latest version: ${error.message}`);
968
- // error.stack && this.log.debug(error.stack);
969
832
  });
970
833
  }
971
- /**
972
- * Retrieves the latest version of a plugin and updates the plugin's latestVersion property.
973
- * If the plugin's version is different from the latest version, logs a warning message.
974
- * If the plugin's version is the same as the latest version, logs an info message.
975
- * If there is an error retrieving the latest version, logs an error message.
976
- *
977
- * @private
978
- * @param {RegisteredPlugin} plugin - The plugin for which to retrieve the latest version.
979
- * @returns {Promise<void>} A promise that resolves when the latest version is retrieved and actions are performed.
980
- */
981
834
  async getPluginLatestVersion(plugin) {
982
835
  this.getLatestVersion(plugin.name)
983
836
  .then(async (latestVersion) => {
@@ -989,54 +842,40 @@ export class Matterbridge extends EventEmitter {
989
842
  })
990
843
  .catch((error) => {
991
844
  this.log.error(`Error getting ${plg}${plugin.name}${er} latest version: ${error.message}`);
992
- // error.stack && this.log.debug(error.stack);
993
845
  });
994
846
  }
995
- /**
996
- * Creates a MatterLogger function to show the matter.js log messages in AnsiLogger (for the frontend).
997
- *
998
- * @returns {Function} The MatterLogger function.
999
- */
1000
847
  createMatterLogger() {
1001
- 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" });
1002
849
  return (_level, formattedLog) => {
1003
850
  const logger = formattedLog.slice(44, 44 + 20).trim();
1004
851
  const message = formattedLog.slice(65);
1005
852
  matterLogger.logName = logger;
1006
853
  switch (_level) {
1007
854
  case MatterLogLevel.DEBUG:
1008
- matterLogger.log("debug" /* LogLevel.DEBUG */, message);
855
+ matterLogger.log("debug", message);
1009
856
  break;
1010
857
  case MatterLogLevel.INFO:
1011
- matterLogger.log("info" /* LogLevel.INFO */, message);
858
+ matterLogger.log("info", message);
1012
859
  break;
1013
860
  case MatterLogLevel.NOTICE:
1014
- matterLogger.log("notice" /* LogLevel.NOTICE */, message);
861
+ matterLogger.log("notice", message);
1015
862
  break;
1016
863
  case MatterLogLevel.WARN:
1017
- matterLogger.log("warn" /* LogLevel.WARN */, message);
864
+ matterLogger.log("warn", message);
1018
865
  break;
1019
866
  case MatterLogLevel.ERROR:
1020
- matterLogger.log("error" /* LogLevel.ERROR */, message);
867
+ matterLogger.log("error", message);
1021
868
  break;
1022
869
  case MatterLogLevel.FATAL:
1023
- matterLogger.log("fatal" /* LogLevel.FATAL */, message);
870
+ matterLogger.log("fatal", message);
1024
871
  break;
1025
872
  default:
1026
- matterLogger.log("debug" /* LogLevel.DEBUG */, message);
873
+ matterLogger.log("debug", message);
1027
874
  break;
1028
875
  }
1029
876
  };
1030
877
  }
1031
- /**
1032
- * Creates a Matter File Logger.
1033
- *
1034
- * @param {string} filePath - The path to the log file.
1035
- * @param {boolean} [unlink=false] - Whether to unlink the log file before creating a new one.
1036
- * @returns {Function} - A function that logs formatted messages to the log file.
1037
- */
1038
878
  async createMatterFileLogger(filePath, unlink = false) {
1039
- // 2024-08-21 08:55:19.488 DEBUG InteractionMessenger Sending DataReport chunk with 28 attributes and 0 events: 1004 bytes
1040
879
  let fileSize = 0;
1041
880
  if (unlink) {
1042
881
  try {
@@ -1085,83 +924,56 @@ export class Matterbridge extends EventEmitter {
1085
924
  }
1086
925
  };
1087
926
  }
1088
- /**
1089
- * Update matterbridge and cleanup.
1090
- */
1091
927
  async updateProcess() {
1092
928
  await this.cleanup('updating...', false);
1093
929
  }
1094
- /**
1095
- * Restarts the process by spawning a new process and exiting the current process.
1096
- */
1097
930
  async restartProcess() {
1098
931
  await this.cleanup('restarting...', true);
1099
932
  }
1100
- /**
1101
- * Shut down the process by exiting the current process.
1102
- */
1103
933
  async shutdownProcess() {
1104
934
  await this.cleanup('shutting down...', false);
1105
935
  }
1106
- /**
1107
- * Shut down the process and reset.
1108
- */
1109
936
  async unregisterAndShutdownProcess() {
1110
937
  this.log.info('Unregistering all devices and shutting down...');
1111
- for (const plugin of this.plugins /* .filter((plugin) => plugin.enabled && !plugin.error))*/) {
1112
- await this.removeAllBridgedDevices(plugin.name);
938
+ for (const plugin of this.plugins) {
939
+ if (this.edge)
940
+ await this.removeAllBridgedEndpoints(plugin.name);
941
+ else
942
+ await this.removeAllBridgedDevices(plugin.name);
1113
943
  }
1114
944
  await this.cleanup('unregistered all devices and shutting down...', false);
1115
945
  }
1116
- /**
1117
- * Shut down the process and reset.
1118
- */
1119
946
  async shutdownProcessAndReset() {
1120
947
  await this.cleanup('shutting down with reset...', false);
1121
948
  }
1122
- /**
1123
- * Shut down the process and factory reset.
1124
- */
1125
949
  async shutdownProcessAndFactoryReset() {
1126
950
  await this.cleanup('shutting down with factory reset...', false);
1127
951
  }
1128
- /**
1129
- * Cleans up the Matterbridge instance.
1130
- * @param message - The cleanup message.
1131
- * @param restart - Indicates whether to restart the instance after cleanup. Default is `false`.
1132
- * @returns A promise that resolves when the cleanup is completed.
1133
- */
1134
952
  async cleanup(message, restart = false) {
1135
953
  if (this.initialized && !this.hasCleanupStarted) {
1136
954
  this.hasCleanupStarted = true;
1137
955
  this.log.info(message);
1138
- // Deregisters the process handlers
1139
956
  this.deregisterProcesslHandlers();
1140
- // Clear the start matter interval
1141
957
  if (this.startMatterInterval) {
1142
958
  clearInterval(this.startMatterInterval);
1143
959
  this.startMatterInterval = undefined;
1144
960
  this.log.debug('Start matter interval cleared');
1145
961
  }
1146
- // Clear the check update interval
1147
962
  if (this.checkUpdateInterval) {
1148
963
  clearInterval(this.checkUpdateInterval);
1149
964
  this.checkUpdateInterval = undefined;
1150
965
  this.log.debug('Check update interval cleared');
1151
966
  }
1152
- // Clear the configure timeout
1153
967
  if (this.configureTimeout) {
1154
968
  clearTimeout(this.configureTimeout);
1155
969
  this.configureTimeout = undefined;
1156
970
  this.log.debug('Matterbridge configure timeout cleared');
1157
971
  }
1158
- // Clear the reachability timeout
1159
972
  if (this.reachabilityTimeout) {
1160
973
  clearTimeout(this.reachabilityTimeout);
1161
974
  this.reachabilityTimeout = undefined;
1162
975
  this.log.debug('Matterbridge reachability timeout cleared');
1163
976
  }
1164
- // Calling the shutdown method of each plugin and clear the reachability timeout
1165
977
  for (const plugin of this.plugins) {
1166
978
  if (!plugin.enabled || plugin.error)
1167
979
  continue;
@@ -1172,29 +984,36 @@ export class Matterbridge extends EventEmitter {
1172
984
  this.log.debug(`Plugin ${plg}${plugin.name}${db} reachability timeout cleared`);
1173
985
  }
1174
986
  }
1175
- // Close the http server
987
+ if (!hasParameter('nostorageconversion') && this.edge === false && this.matterbridgeContext && ['updating...', 'restarting...', 'shutting down...'].includes(message)) {
988
+ if (this.bridgeMode === 'bridge') {
989
+ await this.convertStorage(this.matterbridgeContext, 'Matterbridge');
990
+ }
991
+ else if (this.bridgeMode === 'childbridge') {
992
+ for (const plugin of this.plugins) {
993
+ if (plugin.storageContext) {
994
+ await this.convertStorage(plugin.storageContext, plugin.name);
995
+ }
996
+ }
997
+ }
998
+ }
1176
999
  if (this.httpServer) {
1177
1000
  this.httpServer.close();
1178
1001
  this.httpServer.removeAllListeners();
1179
1002
  this.httpServer = undefined;
1180
1003
  this.log.debug('Frontend http server closed successfully');
1181
1004
  }
1182
- // Close the https server
1183
1005
  if (this.httpsServer) {
1184
1006
  this.httpsServer.close();
1185
1007
  this.httpsServer.removeAllListeners();
1186
1008
  this.httpsServer = undefined;
1187
1009
  this.log.debug('Frontend https server closed successfully');
1188
1010
  }
1189
- // Remove listeners from the express app
1190
1011
  if (this.expressApp) {
1191
1012
  this.expressApp.removeAllListeners();
1192
1013
  this.expressApp = undefined;
1193
1014
  this.log.debug('Frontend app closed successfully');
1194
1015
  }
1195
- // Close the WebSocket server
1196
1016
  if (this.webSocketServer) {
1197
- // Close all active connections
1198
1017
  this.webSocketServer.clients.forEach((client) => {
1199
1018
  if (client.readyState === WebSocket.OPEN) {
1200
1019
  client.close();
@@ -1210,35 +1029,26 @@ export class Matterbridge extends EventEmitter {
1210
1029
  });
1211
1030
  this.webSocketServer = undefined;
1212
1031
  }
1213
- // Closing matter
1214
1032
  await this.stopMatterServer();
1215
- // Closing matter storage
1216
1033
  await this.stopMatterStorage();
1217
- // Remove the matterfilelogger
1218
1034
  try {
1219
1035
  Logger.removeLogger('matterfilelogger');
1220
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1221
1036
  }
1222
1037
  catch (error) {
1223
- // this.log.debug(`Error removing the matterfilelogger for file ${CYAN}${path.join(this.matterbridgeDirectory, this.matterLoggerFile)}${er}: ${error instanceof Error ? error.message : error}`);
1224
1038
  }
1225
- // Serialize registeredDevices
1226
1039
  if (this.nodeStorage && this.nodeContext) {
1227
1040
  this.log.info('Saving registered devices...');
1228
1041
  const serializedRegisteredDevices = [];
1229
1042
  this.devices.forEach(async (device) => {
1230
1043
  const serializedMatterbridgeDevice = device.serialize();
1231
- // this.log.info(`- ${serializedMatterbridgeDevice.deviceName}${rs}\n`, serializedMatterbridgeDevice);
1232
1044
  if (serializedMatterbridgeDevice)
1233
1045
  serializedRegisteredDevices.push(serializedMatterbridgeDevice);
1234
1046
  });
1235
1047
  await this.nodeContext.set('devices', serializedRegisteredDevices);
1236
1048
  this.log.info(`Saved registered devices (${serializedRegisteredDevices?.length})`);
1237
- // Clear nodeContext and nodeStorage (they just need 1000ms to write the data to disk)
1238
1049
  this.log.debug(`Closing node storage context for ${plg}Matterbridge${db}...`);
1239
1050
  await this.nodeContext.close();
1240
1051
  this.nodeContext = undefined;
1241
- // Clear nodeContext for each plugin (they just need 1000ms to write the data to disk)
1242
1052
  for (const plugin of this.plugins) {
1243
1053
  if (plugin.nodeContext) {
1244
1054
  this.log.debug(`Closing node storage context for plugin ${plg}${plugin.name}${db}...`);
@@ -1268,20 +1078,34 @@ export class Matterbridge extends EventEmitter {
1268
1078
  }
1269
1079
  }
1270
1080
  else {
1271
- if (message === 'shutting down with reset...') {
1272
- // Delete matter storage file
1273
- this.log.info('Resetting Matterbridge commissioning information...');
1274
- await fs.unlink(path.join(this.matterbridgeDirectory, this.matterStorageName));
1275
- this.log.info('Reset done! Remove all paired devices from the controllers.');
1081
+ if (message === 'shutting down with reset...' || message === 'shutting down with factory reset...') {
1082
+ try {
1083
+ const file = path.join(this.matterbridgeDirectory, 'matterbridge' + (getParameter('profile') ? '.' + getParameter('profile') : '') + '.json');
1084
+ this.log.info(`Unlinking old matter storage file: ${file}`);
1085
+ await fs.unlink(file);
1086
+ }
1087
+ catch (error) {
1088
+ this.log.debug(`Error resetting old matter storage file: ${error}`);
1089
+ }
1090
+ try {
1091
+ const dir = path.join(this.matterbridgeDirectory, 'matterstorage' + (getParameter('profile') ? '.' + getParameter('profile') : ''));
1092
+ this.log.info(`Removing matter node storage directory: ${dir}`);
1093
+ await fs.rm(dir, { recursive: true });
1094
+ }
1095
+ catch (error) {
1096
+ this.log.debug(`Error resetting matter node storage file: ${error}`);
1097
+ }
1098
+ this.log.info('Reset done! Remove all paired fabrics from the controllers.');
1276
1099
  }
1277
1100
  if (message === 'shutting down with factory reset...') {
1278
- // Delete matter storage file
1279
- this.log.info('Resetting Matterbridge commissioning information...');
1280
- await fs.unlink(path.join(this.matterbridgeDirectory, this.matterStorageName));
1281
- // Delete node storage directory with its subdirectories
1282
- this.log.info('Resetting Matterbridge storage...');
1283
- await fs.rm(path.join(this.matterbridgeDirectory, this.nodeStorageName), { recursive: true });
1284
- this.log.info('Factory reset done! Remove all paired devices from the controllers.');
1101
+ try {
1102
+ this.log.info('Resetting Matterbridge storage...');
1103
+ await fs.rm(path.join(this.matterbridgeDirectory, this.nodeStorageName), { recursive: true });
1104
+ }
1105
+ catch (error) {
1106
+ this.log.debug(`Error resetting Matterbridge storage: ${error}`);
1107
+ }
1108
+ this.log.info('Factory reset done! Remove all paired fabrics from the controllers.');
1285
1109
  }
1286
1110
  this.log.notice('Cleanup completed. Shutting down...');
1287
1111
  Matterbridge.instance = undefined;
@@ -1291,33 +1115,19 @@ export class Matterbridge extends EventEmitter {
1291
1115
  this.initialized = false;
1292
1116
  }
1293
1117
  }
1294
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1295
1118
  async addBridgedEndpoint(pluginName, device) {
1296
- // Nothing to do here
1297
1119
  }
1298
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1299
1120
  async removeBridgedEndpoint(pluginName, device) {
1300
- // Nothing to do here
1301
1121
  }
1302
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1303
1122
  async removeAllBridgedEndpoints(pluginName) {
1304
- // Nothing to do here
1305
1123
  }
1306
- /**
1307
- * Adds a bridged device to the Matterbridge.
1308
- * @param pluginName - The name of the plugin.
1309
- * @param device - The bridged device to add.
1310
- * @returns {Promise<void>} - A promise that resolves when the device is added.
1311
- */
1312
1124
  async addBridgedDevice(pluginName, device) {
1313
1125
  this.log.debug(`Adding bridged device ${dev}${device.deviceName}${db} (${zb}${device.name}${db}) for plugin ${plg}${pluginName}${db}`);
1314
- // Check if the plugin is registered
1315
1126
  const plugin = this.plugins.get(pluginName);
1316
1127
  if (!plugin) {
1317
1128
  this.log.error(`Error adding bridged device ${dev}${device.deviceName}${er} (${zb}${device.name}${er}) plugin ${plg}${pluginName}${er} not found`);
1318
1129
  return;
1319
1130
  }
1320
- // Register and add the device to matterbridge aggregator in bridge mode
1321
1131
  if (this.bridgeMode === 'bridge') {
1322
1132
  if (!this.matterAggregator) {
1323
1133
  this.log.error(`Adding bridged device ${dev}${device.deviceName}${er} (${zb}${device.name}${er}) for plugin ${plg}${pluginName}${er} error: matterAggregator not found`);
@@ -1325,11 +1135,8 @@ export class Matterbridge extends EventEmitter {
1325
1135
  }
1326
1136
  this.matterAggregator.addBridgedDevice(device);
1327
1137
  }
1328
- // The first time create the commissioning server and the aggregator for DynamicPlatform
1329
- // Register and add the device in childbridge mode
1330
1138
  if (this.bridgeMode === 'childbridge') {
1331
1139
  if (plugin.type === 'AccessoryPlatform') {
1332
- // Check if the plugin is locked with the commissioning server
1333
1140
  if (!plugin.locked) {
1334
1141
  plugin.locked = true;
1335
1142
  plugin.storageContext = await this.importCommissioningServerContext(plugin.name, device);
@@ -1343,7 +1150,6 @@ export class Matterbridge extends EventEmitter {
1343
1150
  }
1344
1151
  }
1345
1152
  if (plugin.type === 'DynamicPlatform') {
1346
- // Check if the plugin is locked with the commissioning server and the aggregator
1347
1153
  if (!plugin.locked) {
1348
1154
  plugin.locked = true;
1349
1155
  this.log.debug(`Creating commissioning server context for ${plg}${plugin.name}${db}`);
@@ -1364,25 +1170,16 @@ export class Matterbridge extends EventEmitter {
1364
1170
  plugin.registeredDevices++;
1365
1171
  if (plugin.addedDevices !== undefined)
1366
1172
  plugin.addedDevices++;
1367
- // Add the device to the DeviceManager
1368
1173
  this.devices.set(device);
1369
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}`);
1370
1175
  }
1371
- /**
1372
- * Removes a bridged device from the Matterbridge.
1373
- * @param pluginName - The name of the plugin.
1374
- * @param device - The device to be removed.
1375
- * @returns A Promise that resolves when the device is successfully removed.
1376
- */
1377
1176
  async removeBridgedDevice(pluginName, device) {
1378
1177
  this.log.debug(`Removing bridged device ${dev}${device.deviceName}${db} (${zb}${device.name}${db}) for plugin ${plg}${pluginName}${db}`);
1379
- // Check if the plugin is registered
1380
1178
  const plugin = this.plugins.get(pluginName);
1381
1179
  if (!plugin) {
1382
1180
  this.log.error(`Error removing bridged device ${dev}${device.deviceName}${er} (${zb}${device.name}${er}) for plugin ${plg}${pluginName}${er}: plugin not found`);
1383
1181
  return;
1384
1182
  }
1385
- // Remove the device from matterbridge aggregator in bridge mode
1386
1183
  if (this.bridgeMode === 'bridge') {
1387
1184
  if (!this.matterAggregator) {
1388
1185
  this.log.error(`Error removing bridged device ${dev}${device.deviceName}${er} (${zb}${device.name}${er}) for plugin ${plg}${pluginName}${er}: matterAggregator not found`);
@@ -1392,8 +1189,6 @@ export class Matterbridge extends EventEmitter {
1392
1189
  device.setBridgedDeviceReachability(false);
1393
1190
  device.getClusterServerById(BridgedDeviceBasicInformation.Cluster.id)?.triggerReachableChangedEvent({ reachableNewValue: false });
1394
1191
  }
1395
- // device.getClusterServerById(BridgedDeviceBasicInformation.Cluster.id)?.triggerShutDownEvent({});
1396
- // device.getClusterServerById(BridgedDeviceBasicInformation.Cluster.id)?.triggerLeaveEvent({});
1397
1192
  this.matterAggregator?.removeBridgedDevice(device);
1398
1193
  this.log.info(`Removed bridged device(${plugin.registeredDevices}/${plugin.addedDevices}) ${dev}${device.deviceName}${nf} (${zb}${device.name}${nf}) for plugin ${plg}${pluginName}${nf}`);
1399
1194
  if (plugin.registeredDevices !== undefined)
@@ -1401,7 +1196,6 @@ export class Matterbridge extends EventEmitter {
1401
1196
  if (plugin.addedDevices !== undefined)
1402
1197
  plugin.addedDevices--;
1403
1198
  }
1404
- // Remove the device in childbridge mode
1405
1199
  if (this.bridgeMode === 'childbridge') {
1406
1200
  if (plugin.type === 'AccessoryPlatform') {
1407
1201
  if (!plugin.commissioningServer) {
@@ -1425,22 +1219,14 @@ export class Matterbridge extends EventEmitter {
1425
1219
  plugin.registeredDevices--;
1426
1220
  if (plugin.addedDevices !== undefined)
1427
1221
  plugin.addedDevices--;
1428
- // Remove the commissioning server
1429
1222
  if (plugin.registeredDevices === 0 && plugin.addedDevices === 0 && plugin.commissioningServer) {
1430
1223
  this.matterServer?.removeCommissioningServer(plugin.commissioningServer);
1431
1224
  plugin.commissioningServer = undefined;
1432
1225
  this.log.info(`Removed commissioning server for plugin ${plg}${pluginName}${nf}`);
1433
1226
  }
1434
1227
  }
1435
- // Remove the device from the DeviceManager
1436
1228
  this.devices.remove(device);
1437
1229
  }
1438
- /**
1439
- * Removes all bridged devices associated with a specific plugin.
1440
- *
1441
- * @param pluginName - The name of the plugin.
1442
- * @returns A promise that resolves when all devices have been removed.
1443
- */
1444
1230
  async removeAllBridgedDevices(pluginName) {
1445
1231
  this.log.debug(`Removing all bridged devices for plugin ${plg}${pluginName}${db}`);
1446
1232
  this.devices.forEach(async (device) => {
@@ -1449,13 +1235,7 @@ export class Matterbridge extends EventEmitter {
1449
1235
  }
1450
1236
  });
1451
1237
  }
1452
- /**
1453
- * Starts the Matterbridge in bridge mode.
1454
- * @private
1455
- * @returns {Promise<void>} A promise that resolves when the Matterbridge is started.
1456
- */
1457
1238
  async startBridge() {
1458
- // Plugins are configured by a timer when matter server is started and plugin.configured is set to true
1459
1239
  if (!this.storageManager)
1460
1240
  throw new Error('No storage manager initialized');
1461
1241
  if (!this.matterbridgeContext)
@@ -1474,7 +1254,6 @@ export class Matterbridge extends EventEmitter {
1474
1254
  let failCount = 0;
1475
1255
  this.startMatterInterval = setInterval(async () => {
1476
1256
  for (const plugin of this.plugins) {
1477
- // new code to not start the bridge if one plugin is in error cause the controllers will delete the devices loosing all the configuration
1478
1257
  if (!plugin.enabled)
1479
1258
  continue;
1480
1259
  if (plugin.error) {
@@ -1499,18 +1278,15 @@ export class Matterbridge extends EventEmitter {
1499
1278
  clearInterval(this.startMatterInterval);
1500
1279
  this.startMatterInterval = undefined;
1501
1280
  this.log.debug('Cleared startMatterInterval interval for Matterbridge');
1502
- // Start the Matter server
1503
1281
  await this.startMatterServer();
1504
1282
  this.log.notice('Matter server started');
1505
- // Show the QR code for commissioning or log the already commissioned message
1506
1283
  await this.showCommissioningQRCode(this.commissioningServer, this.matterbridgeContext, this.nodeContext, 'Matterbridge');
1507
- // Configure the plugins
1508
1284
  this.configureTimeout = setTimeout(async () => {
1509
1285
  for (const plugin of this.plugins) {
1510
1286
  if (!plugin.enabled || !plugin.loaded || !plugin.started || plugin.error)
1511
1287
  continue;
1512
1288
  try {
1513
- await this.plugins.configure(plugin); // TODO No await do it in parallel
1289
+ await this.plugins.configure(plugin);
1514
1290
  }
1515
1291
  catch (error) {
1516
1292
  plugin.error = true;
@@ -1519,7 +1295,6 @@ export class Matterbridge extends EventEmitter {
1519
1295
  }
1520
1296
  this.wssSendRefreshRequired();
1521
1297
  }, 30 * 1000);
1522
- // Setting reachability to true
1523
1298
  this.reachabilityTimeout = setTimeout(() => {
1524
1299
  this.log.info(`Setting reachability to true for ${plg}Matterbridge${db}`);
1525
1300
  if (this.commissioningServer)
@@ -1529,14 +1304,7 @@ export class Matterbridge extends EventEmitter {
1529
1304
  }, 60 * 1000);
1530
1305
  }, 1000);
1531
1306
  }
1532
- /**
1533
- * Starts the Matterbridge in childbridge mode.
1534
- * @private
1535
- * @returns {Promise<void>} A promise that resolves when the Matterbridge is started.
1536
- */
1537
1307
  async startChildbridge() {
1538
- // Matterbridge.addBridgedDevice creates the commissionig servers and add the devices to the the commissioning server or to the aggregator
1539
- // Plugins are configured by a timer when matter server is started and plugin.configured is set to true
1540
1308
  if (!this.storageManager)
1541
1309
  throw new Error('No storage manager initialized');
1542
1310
  this.matterServer = this.createMatterServer(this.storageManager);
@@ -1546,7 +1314,6 @@ export class Matterbridge extends EventEmitter {
1546
1314
  this.startMatterInterval = setInterval(async () => {
1547
1315
  let allStarted = true;
1548
1316
  for (const plugin of this.plugins) {
1549
- // new code to not start the bridge if one plugin is in error cause the controllers will delete the devices loosing all the configuration
1550
1317
  if (!plugin.enabled)
1551
1318
  continue;
1552
1319
  if (plugin.error) {
@@ -1574,16 +1341,14 @@ export class Matterbridge extends EventEmitter {
1574
1341
  clearInterval(this.startMatterInterval);
1575
1342
  this.startMatterInterval = undefined;
1576
1343
  this.log.debug('Cleared startMatterInterval interval in childbridge mode');
1577
- // Start the Matter server
1578
1344
  await this.startMatterServer();
1579
1345
  this.log.notice('Matter server started');
1580
- // Configure the plugins
1581
1346
  this.configureTimeout = setTimeout(async () => {
1582
1347
  for (const plugin of this.plugins) {
1583
1348
  if (!plugin.enabled || !plugin.loaded || !plugin.started || plugin.error)
1584
1349
  continue;
1585
1350
  try {
1586
- await this.plugins.configure(plugin); // TODO No await do it in parallel
1351
+ await this.plugins.configure(plugin);
1587
1352
  }
1588
1353
  catch (error) {
1589
1354
  plugin.error = true;
@@ -1612,7 +1377,6 @@ export class Matterbridge extends EventEmitter {
1612
1377
  continue;
1613
1378
  }
1614
1379
  await this.showCommissioningQRCode(plugin.commissioningServer, plugin.storageContext, plugin.nodeContext, plugin.name);
1615
- // Setting reachability to true
1616
1380
  plugin.reachabilityTimeout = setTimeout(() => {
1617
1381
  this.log.info(`Setting reachability to true for ${plg}${plugin.name}${db}`);
1618
1382
  if (plugin.commissioningServer)
@@ -1625,11 +1389,6 @@ export class Matterbridge extends EventEmitter {
1625
1389
  }
1626
1390
  }, 1000);
1627
1391
  }
1628
- /**
1629
- * Starts the Matterbridge controller.
1630
- * @private
1631
- * @returns {Promise<void>} A promise that resolves when the Matterbridge is started.
1632
- */
1633
1392
  async startController() {
1634
1393
  if (!this.storageManager) {
1635
1394
  this.log.error('No storage manager initialized');
@@ -1692,7 +1451,7 @@ export class Matterbridge extends EventEmitter {
1692
1451
  const nodeId = await this.commissioningController.commissionNode(options);
1693
1452
  this.log.info(`Commissioning successfully done with nodeId: ${nodeId}`);
1694
1453
  this.log.info('ActiveSessionInformation:', this.commissioningController.getActiveSessionInformation());
1695
- } // (hasParameter('pairingcode'))
1454
+ }
1696
1455
  if (hasParameter('unpairall')) {
1697
1456
  this.log.info('***Commissioning controller unpairing all nodes...');
1698
1457
  const nodeIds = this.commissioningController.getCommissionedNodes();
@@ -1703,8 +1462,6 @@ export class Matterbridge extends EventEmitter {
1703
1462
  return;
1704
1463
  }
1705
1464
  if (hasParameter('discover')) {
1706
- // const discover = await this.commissioningController.discoverCommissionableDevices({ productId: 0x8000, deviceType: 0xfff1 });
1707
- // console.log(discover);
1708
1465
  }
1709
1466
  if (!this.commissioningController.isCommissioned()) {
1710
1467
  this.log.info('***Commissioning controller is not commissioned: use matterbridge -controller -pairingcode [pairingcode] to commission a device');
@@ -1745,12 +1502,10 @@ export class Matterbridge extends EventEmitter {
1745
1502
  },
1746
1503
  });
1747
1504
  node.logStructure();
1748
- // Get the interaction client
1749
1505
  this.log.info('Getting the interaction client');
1750
1506
  const interactionClient = await node.getInteractionClient();
1751
1507
  let cluster;
1752
1508
  let attributes;
1753
- // Log BasicInformationCluster
1754
1509
  cluster = BasicInformationCluster;
1755
1510
  attributes = await interactionClient.getMultipleAttributes({
1756
1511
  attributes: [{ clusterId: cluster.id }],
@@ -1760,7 +1515,6 @@ export class Matterbridge extends EventEmitter {
1760
1515
  attributes.forEach((attribute) => {
1761
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}`);
1762
1517
  });
1763
- // Log PowerSourceCluster
1764
1518
  cluster = PowerSourceCluster;
1765
1519
  attributes = await interactionClient.getMultipleAttributes({
1766
1520
  attributes: [{ clusterId: cluster.id }],
@@ -1770,7 +1524,6 @@ export class Matterbridge extends EventEmitter {
1770
1524
  attributes.forEach((attribute) => {
1771
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}`);
1772
1526
  });
1773
- // Log ThreadNetworkDiagnostics
1774
1527
  cluster = ThreadNetworkDiagnosticsCluster;
1775
1528
  attributes = await interactionClient.getMultipleAttributes({
1776
1529
  attributes: [{ clusterId: cluster.id }],
@@ -1780,7 +1533,6 @@ export class Matterbridge extends EventEmitter {
1780
1533
  attributes.forEach((attribute) => {
1781
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}`);
1782
1535
  });
1783
- // Log SwitchCluster
1784
1536
  cluster = SwitchCluster;
1785
1537
  attributes = await interactionClient.getMultipleAttributes({
1786
1538
  attributes: [{ clusterId: cluster.id }],
@@ -1801,15 +1553,6 @@ export class Matterbridge extends EventEmitter {
1801
1553
  this.log.info('Subscribed to all attributes and events');
1802
1554
  }
1803
1555
  }
1804
- /** ***********************************************************************************************************************************/
1805
- /** Matter.js methods */
1806
- /** ***********************************************************************************************************************************/
1807
- /**
1808
- * Starts the matter storage process based on the specified storage type and name.
1809
- * @param {string} storageType - The type of storage to start (e.g., 'disk', 'json').
1810
- * @param {string} storageName - The name of the storage file.
1811
- * @returns {Promise<void>} - A promise that resolves when the storage process is started.
1812
- */
1813
1556
  async startMatterStorage(storageType, storageName) {
1814
1557
  this.log.debug(`Starting matter ${storageType} storage ${CYAN}${storageName}${db}`);
1815
1558
  if (storageType === 'disk') {
@@ -1854,13 +1597,186 @@ export class Matterbridge extends EventEmitter {
1854
1597
  }
1855
1598
  this.log.debug(`Creating commissioning server context for ${plg}Matterbridge${db}`);
1856
1599
  this.matterbridgeContext = await this.createCommissioningServerContext('Matterbridge', 'Matterbridge', aggregator.code, 0xfff1, 'Matterbridge', 0x8000, 'Matterbridge aggregator');
1600
+ await this.matterbridgeContext.set('port', this.port);
1601
+ await this.matterbridgeContext.set('passcode', this.passcode);
1602
+ await this.matterbridgeContext.set('discriminator', this.discriminator);
1603
+ }
1604
+ async convertStorage(context, pluginName) {
1605
+ if (this.edge !== false)
1606
+ return;
1607
+ try {
1608
+ const storageService = Environment.default.get(StorageService);
1609
+ Environment.default.vars.set('path.root', path.join(this.matterbridgeDirectory, 'matterstorage' + (this.profile ? '.' + this.profile : '')));
1610
+ const nodeStorage = await storageService.open(pluginName);
1611
+ if ((await nodeStorage.createContext('root').createContext('generalDiagnostics').get('rebootCount', -1)) >= 0) {
1612
+ this.log.info(`Matter node storage already converted to Matterbridge edge for ${plg}${pluginName}${nf}`);
1613
+ return;
1614
+ }
1615
+ else {
1616
+ this.log.notice(`Converting matter node storage to Matterbridge edge for ${plg}${pluginName}${nt}...`);
1617
+ }
1618
+ const fabricManagerContext = context.createContext('FabricManager');
1619
+ const fabrics = (await fabricManagerContext.get('fabrics', []));
1620
+ const nextFabricIndex = await fabricManagerContext.get('nextFabricIndex', 0);
1621
+ const eventHandlerContext = context.createContext('EventHandler');
1622
+ const sessionManagerContext = context.createContext('SessionManager');
1623
+ const endpointStructureContext = context.createContext('EndpointStructure');
1624
+ const generalCommissioningContext = context.createContext('Cluster-0-48');
1625
+ const basicInformationContext = context.createContext('Cluster-0-40');
1626
+ const fabricInfo = {};
1627
+ const fabricInfoArray = [];
1628
+ const nocArray = [];
1629
+ const trcArray = [];
1630
+ const aclArray = [];
1631
+ this.log.info(`Found ${CYAN}${fabrics.length}${nf} fabrics (nextFabricIndex ${CYAN}${nextFabricIndex}${nf}) for ${plg}${pluginName}${nf}:`);
1632
+ if (fabrics.length === 0 || nextFabricIndex === 0) {
1633
+ this.log.notice(`If you want to try out matterbridge edge (beta) add -edge to the command line and pair it to your controller(s).`);
1634
+ return;
1635
+ }
1636
+ for (const fabric of fabrics) {
1637
+ this.log.info(`- fabricIndex ${CYAN}${fabric.fabricIndex}${nf} fabricId ${CYAN}${fabric.fabricId}${nf} nodeId ${CYAN}${fabric.nodeId}${nf} rootNodeId ${CYAN}${fabric.rootNodeId}${nf} rootVendorId ${CYAN}${fabric.rootVendorId}${nf} label ${CYAN}${fabric.label}${nf}`);
1638
+ fabricInfo[fabric.fabricIndex] = {
1639
+ fabricIndex: fabric.fabricIndex,
1640
+ fabricId: fabric.fabricId,
1641
+ nodeId: fabric.nodeId,
1642
+ rootNodeId: fabric.rootNodeId,
1643
+ rootVendorId: fabric.rootVendorId,
1644
+ label: fabric.label,
1645
+ };
1646
+ fabricInfoArray.push({
1647
+ fabricIndex: fabric.fabricIndex,
1648
+ fabricId: fabric.fabricId,
1649
+ nodeId: fabric.nodeId,
1650
+ vendorId: fabric.rootVendorId,
1651
+ rootPublicKey: fabric.rootPublicKey,
1652
+ label: fabric.label,
1653
+ });
1654
+ nocArray.push({ noc: fabric.operationalCert, icac: null, fabricIndex: fabric.fabricIndex });
1655
+ trcArray.push(fabric.rootCert);
1656
+ this.log.info(`- updating ACL for fabricIndex ${fabric.fabricIndex}:`, fabric.scopedClusterData);
1657
+ const acl = fabric.scopedClusterData.get(0x1f)?.get('acl');
1658
+ if (acl && acl.value.length > 0) {
1659
+ aclArray.push(acl.value[0]);
1660
+ this.log.info(`- ACL updated to ${debugStringify(acl.value)}${nf} for fabricIndex ${CYAN}${fabric.fabricIndex}${nf}`);
1661
+ }
1662
+ else {
1663
+ const defaultAcl = { fabricIndex: fabric.fabricIndex, privilege: 5, authMode: 2, subjects: [fabric.rootNodeId], targets: null };
1664
+ aclArray.push(defaultAcl);
1665
+ this.log.info(`- ACL updated to default ${debugStringify(defaultAcl)}${nf} for fabricIndex ${CYAN}${fabric.fabricIndex}${nf}`);
1666
+ }
1667
+ }
1668
+ await nodeStorage.createContext('fabrics').set('fabrics', fabrics);
1669
+ await nodeStorage.createContext('fabrics').set('nextFabricIndex', nextFabricIndex);
1670
+ await nodeStorage.createContext('sessions').set('resumptionRecords', await sessionManagerContext.get('resumptionRecords', []));
1671
+ await nodeStorage.createContext('events').set('lastEventNumber', await eventHandlerContext.get('lastEventNumber', 1));
1672
+ await nodeStorage.createContext('root').set('__number__', 0);
1673
+ await nodeStorage.createContext('root').createContext('commissioning').set('enabled', true);
1674
+ await nodeStorage.createContext('root').createContext('commissioning').set('commissioned', true);
1675
+ await nodeStorage.createContext('root').createContext('commissioning').set('fabrics', fabricInfo);
1676
+ await nodeStorage.createContext('root').createContext('operationalCredentials').set('commissionedFabrics', fabricInfoArray.length);
1677
+ await nodeStorage.createContext('root').createContext('operationalCredentials').set('fabrics', fabricInfoArray);
1678
+ await nodeStorage.createContext('root').createContext('operationalCredentials').set('nocs', nocArray);
1679
+ await nodeStorage.createContext('root').createContext('operationalCredentials').set('trustedRootCertificates', trcArray);
1680
+ await nodeStorage.createContext('root').createContext('accessControl').set('acl', aclArray);
1681
+ await nodeStorage
1682
+ .createContext('root')
1683
+ .createContext('generalCommissioning')
1684
+ .set('breadcrumb', await generalCommissioningContext.get('breadcrumb', BigInt(0)));
1685
+ await nodeStorage
1686
+ .createContext('root')
1687
+ .createContext('basicInformation')
1688
+ .set('location', await basicInformationContext.get('location', 'XX'));
1689
+ await nodeStorage.createContext('root').createContext('network').set('ble', false);
1690
+ await nodeStorage
1691
+ .createContext('root')
1692
+ .createContext('network')
1693
+ .set('operationalPort', await context.get('port', 5540));
1694
+ await nodeStorage
1695
+ .createContext('root')
1696
+ .createContext('productDescription')
1697
+ .set('productId', await context.get('productId', 0x8000));
1698
+ await nodeStorage
1699
+ .createContext('root')
1700
+ .createContext('productDescription')
1701
+ .set('vendorId', await context.get('vendorId', 0xfff1));
1702
+ const rootDeviceName = (await context.get('deviceName', '')).replace(/[ .]/g, '');
1703
+ this.log.info(`Converting ${pluginName}.EndpointStructure to root.parts.${rootDeviceName}...`);
1704
+ for (const key of await endpointStructureContext.keys()) {
1705
+ if (key === 'nextEndpointId') {
1706
+ await nodeStorage.createContext('root').set('__nextNumber__', await endpointStructureContext.get(key));
1707
+ continue;
1708
+ }
1709
+ const parts = key.split('-');
1710
+ const number = await endpointStructureContext.get(key);
1711
+ if (parts.length === 2) {
1712
+ this.log.debug(`Converting bridge Matterbridge.EndpointStructure:${key}:${number} to root.parts.${rootDeviceName}.__number__:${CYAN}${number}${db}`);
1713
+ await nodeStorage.createContext('root').createContext('parts').createContext(rootDeviceName).set('__number__', number);
1714
+ }
1715
+ else if (parts.length === 3 && parts[2].startsWith('unique_')) {
1716
+ const device = this.devices.get(parts[2].replace('unique_', ''));
1717
+ if (device && device.deviceName && device.maybeNumber) {
1718
+ this.log.debug(`Converting unique Matterbridge.EndpointStructure:${key}:${number} to root.parts.${rootDeviceName}.parts.${device.deviceName.replace(/[ .]/g, '')}.__number__:${CYAN}${device.maybeNumber}${db}`);
1719
+ await nodeStorage.createContext('root').createContext('parts').createContext(rootDeviceName).createContext('parts').createContext(device.deviceName.replace(/[ .]/g, '')).set('__number__', device.maybeNumber);
1720
+ }
1721
+ }
1722
+ else if (parts.length === 4 && parts[2].startsWith('unique_') && parts[3].startsWith('custom_')) {
1723
+ const device = this.devices.get(parts[2].replace('unique_', ''));
1724
+ if (device && device.deviceName && device.maybeNumber) {
1725
+ const childEndpointName = parts[3].replace('custom_', '');
1726
+ const childEndpoint = device.getChildEndpointByName(childEndpointName);
1727
+ this.log.debug(`Converting unique Matterbridge.EndpointStructure:${key}:${number} to root.parts.${rootDeviceName}.parts.${device.deviceName.replace(/[ .]/g, '')}.parts.${parts[3].replace('custom_', '').replace(/[ .]/g, '')}.__number__:${CYAN}${childEndpoint?.number}${db}`);
1728
+ await nodeStorage
1729
+ .createContext('root')
1730
+ .createContext('parts')
1731
+ .createContext(rootDeviceName)
1732
+ .createContext('parts')
1733
+ .createContext(device.deviceName.replace(/[ .]/g, ''))
1734
+ .createContext('parts')
1735
+ .createContext(parts[3].replace('custom_', '').replace(/[ .]/g, ''))
1736
+ .set('__number__', childEndpoint?.number);
1737
+ }
1738
+ }
1739
+ else if (parts.length === 3 && parts[2].startsWith('custom_')) {
1740
+ this.log.debug(`Converting custom Matterbridge.EndpointStructure:${key}:${number} to root.parts.${rootDeviceName}.parts.${parts[2].replace('custom_', '').replace(/[ .]/g, '')}.__number__:${CYAN}${number}${db}`);
1741
+ await nodeStorage.createContext('root').createContext('parts').createContext(rootDeviceName).createContext('parts').createContext(parts[2].replace('custom_', '').replace(/[ .]/g, '')).set('__number__', number);
1742
+ }
1743
+ else if (parts.length === 4 && parts[2].startsWith('custom_') && parts[3].startsWith('custom_')) {
1744
+ this.log.debug(`Converting custom Matterbridge.EndpointStructure:${key}:${number} to root.parts.${rootDeviceName}.parts.${parts[2].replace('custom_', '').replace(/[ .]/g, '')}.parts.${parts[3].replace('custom_', '').replace(/[ .]/g, '')}.__number__:${CYAN}${number}${db}`);
1745
+ await nodeStorage
1746
+ .createContext('root')
1747
+ .createContext('parts')
1748
+ .createContext(rootDeviceName)
1749
+ .createContext('parts')
1750
+ .createContext(parts[2].replace('custom_', '').replace(/[ .]/g, ''))
1751
+ .createContext('parts')
1752
+ .createContext(parts[3].replace('custom_', '').replace(/[ .]/g, ''))
1753
+ .set('__number__', number);
1754
+ }
1755
+ }
1756
+ await nodeStorage.createContext('persist').set('converted', true);
1757
+ await nodeStorage.createContext('persist').set('deviceName', await context.get('deviceName'));
1758
+ await nodeStorage.createContext('persist').set('deviceType', await context.get('deviceType'));
1759
+ await nodeStorage.createContext('persist').set('vendorId', await context.get('vendorId'));
1760
+ await nodeStorage.createContext('persist').set('vendorName', await context.get('vendorName'));
1761
+ await nodeStorage.createContext('persist').set('productId', await context.get('productId'));
1762
+ await nodeStorage.createContext('persist').set('productName', await context.get('productName'));
1763
+ await nodeStorage.createContext('persist').set('nodeLabel', await context.get('nodeLabel'));
1764
+ await nodeStorage.createContext('persist').set('productLabel', await context.get('productLabel'));
1765
+ await nodeStorage.createContext('persist').set('serialNumber', 'SN' + (await context.get('serialNumber')));
1766
+ await nodeStorage.createContext('persist').set('uniqueId', await context.get('uniqueId'));
1767
+ await nodeStorage.createContext('persist').set('softwareVersion', await context.get('softwareVersion'));
1768
+ await nodeStorage.createContext('persist').set('softwareVersionString', await context.get('softwareVersionString'));
1769
+ await nodeStorage.createContext('persist').set('hardwareVersion', await context.get('hardwareVersion'));
1770
+ await nodeStorage.createContext('persist').set('hardwareVersionString', await context.get('hardwareVersionString'));
1771
+ await context.set('converted', true);
1772
+ this.log.notice(`Matter storage converted to Matterbridge edge for ${plg}${pluginName}${nt}`);
1773
+ this.log.notice(`If you want to try out matterbridge edge (beta) add -edge to the command line.`);
1774
+ this.log.notice(`All fabrics have been converted to the new storage format.`);
1775
+ }
1776
+ catch (error) {
1777
+ this.log.error(`convertStorage error converting matter storage to Matterbridge edge for ${plg}${pluginName}${er}:`, error);
1778
+ }
1857
1779
  }
1858
- /**
1859
- * Makes a backup copy of the specified matter JSON storage file.
1860
- *
1861
- * @param storageName - The name of the JSON storage file to be backed up.
1862
- * @param backupName - The name of the backup file to be created.
1863
- */
1864
1780
  async backupMatterStorage(storageName, backupName) {
1865
1781
  try {
1866
1782
  this.log.debug(`Making backup copy of ${storageName}`);
@@ -1881,12 +1797,6 @@ export class Matterbridge extends EventEmitter {
1881
1797
  }
1882
1798
  }
1883
1799
  }
1884
- /**
1885
- * Restore the specified matter JSON storage file.
1886
- *
1887
- * @param backupName - The name of the backup file to restore from.
1888
- * @param storageName - The name of the JSON storage file to restored.
1889
- */
1890
1800
  async restoreMatterStorage(backupName, storageName) {
1891
1801
  try {
1892
1802
  this.log.notice(`Restoring the backup copy of ${storageName}`);
@@ -1907,10 +1817,6 @@ export class Matterbridge extends EventEmitter {
1907
1817
  }
1908
1818
  }
1909
1819
  }
1910
- /**
1911
- * Stops the matter storage.
1912
- * @returns {Promise<void>} A promise that resolves when the storage is stopped.
1913
- */
1914
1820
  async stopMatterStorage() {
1915
1821
  this.log.debug('Stopping storage');
1916
1822
  await this.storageManager?.close();
@@ -1919,14 +1825,8 @@ export class Matterbridge extends EventEmitter {
1919
1825
  this.matterbridgeContext = undefined;
1920
1826
  this.mattercontrollerContext = undefined;
1921
1827
  }
1922
- /**
1923
- * Creates a Matter server using the provided storage manager and the provided mdnsInterface.
1924
- * @param storageManager The storage manager to be used by the Matter server.
1925
- *
1926
- */
1927
1828
  createMatterServer(storageManager) {
1928
1829
  this.log.debug('Creating matter server');
1929
- // Validate mdnsInterface
1930
1830
  if (this.mdnsInterface) {
1931
1831
  const networkInterfaces = os.networkInterfaces();
1932
1832
  const availableInterfaces = Object.keys(networkInterfaces);
@@ -1942,10 +1842,6 @@ export class Matterbridge extends EventEmitter {
1942
1842
  this.log.debug(`Created matter server with mdnsInterface: ${this.mdnsInterface ?? 'all available interfaces'}`);
1943
1843
  return matterServer;
1944
1844
  }
1945
- /**
1946
- * Starts the Matter server.
1947
- * If the Matter server is not initialized, it logs an error and performs cleanup.
1948
- */
1949
1845
  async startMatterServer() {
1950
1846
  if (!this.matterServer) {
1951
1847
  this.log.error('No matter server initialized');
@@ -1955,11 +1851,7 @@ export class Matterbridge extends EventEmitter {
1955
1851
  this.log.debug('Starting matter server...');
1956
1852
  await this.matterServer.start();
1957
1853
  this.log.debug('Started matter server');
1958
- // this.commissioningServer?.getRootEndpoint() && logEndpoint(this.commissioningServer?.getRootEndpoint());
1959
1854
  }
1960
- /**
1961
- * Stops the Matter server, commissioningServer and commissioningController.
1962
- */
1963
1855
  async stopMatterServer() {
1964
1856
  this.log.debug('Stopping matter commissioningServer');
1965
1857
  await this.commissioningServer?.close();
@@ -1973,35 +1865,23 @@ export class Matterbridge extends EventEmitter {
1973
1865
  this.matterAggregator = undefined;
1974
1866
  this.matterServer = undefined;
1975
1867
  }
1976
- /**
1977
- * Creates a Matter Aggregator.
1978
- * @param {StorageContext} context - The storage context.
1979
- * @returns {Aggregator} - The created Matter Aggregator.
1980
- */
1981
1868
  async createMatterAggregator(context, pluginName) {
1982
1869
  this.log.debug(`Creating matter aggregator for ${plg}${pluginName}${db}`);
1983
1870
  const matterAggregator = new Aggregator();
1984
1871
  return matterAggregator;
1985
1872
  }
1986
- /**
1987
- * Creates a matter commissioning server.
1988
- *
1989
- * @param {StorageContext} context - The storage context.
1990
- * @param {string} pluginName - The name of the commissioning server.
1991
- * @returns {CommissioningServer} The created commissioning server.
1992
- */
1993
1873
  async createCommisioningServer(context, pluginName) {
1994
1874
  this.log.debug(`Creating matter commissioning server for plugin ${plg}${pluginName}${db}`);
1995
1875
  const deviceName = await context.get('deviceName');
1996
1876
  const deviceType = await context.get('deviceType');
1997
1877
  const vendorId = await context.get('vendorId');
1998
- const vendorName = await context.get('vendorName'); // Home app = Manufacturer
1878
+ const vendorName = await context.get('vendorName');
1999
1879
  const productId = await context.get('productId');
2000
- const productName = await context.get('productName'); // Home app = Model
1880
+ const productName = await context.get('productName');
2001
1881
  const serialNumber = await context.get('serialNumber');
2002
1882
  const uniqueId = await context.get('uniqueId');
2003
1883
  const softwareVersion = await context.get('softwareVersion', 1);
2004
- const softwareVersionString = await context.get('softwareVersionString', '1.0.0'); // Home app = Firmware Revision
1884
+ const softwareVersionString = await context.get('softwareVersionString', '1.0.0');
2005
1885
  const hardwareVersion = await context.get('hardwareVersion', 1);
2006
1886
  const hardwareVersionString = await context.get('hardwareVersionString', '1.0.0');
2007
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')})`);
@@ -2009,7 +1889,6 @@ export class Matterbridge extends EventEmitter {
2009
1889
  this.log.debug(`Creating matter commissioning server for plugin ${plg}${pluginName}${db} with softwareVersion ${softwareVersion} softwareVersionString ${softwareVersionString}`);
2010
1890
  this.log.debug(`Creating matter commissioning server for plugin ${plg}${pluginName}${db} with hardwareVersion ${hardwareVersion} hardwareVersionString ${hardwareVersionString}`);
2011
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} `);
2012
- // Validate ipv4address
2013
1892
  if (this.ipv4address) {
2014
1893
  const networkInterfaces = os.networkInterfaces();
2015
1894
  const availableAddresses = Object.values(networkInterfaces)
@@ -2024,7 +1903,6 @@ export class Matterbridge extends EventEmitter {
2024
1903
  this.log.info(`Using ipv4address '${this.ipv4address}' for the Matter commissioning server.`);
2025
1904
  }
2026
1905
  }
2027
- // Validate ipv6address
2028
1906
  if (this.ipv6address) {
2029
1907
  const networkInterfaces = os.networkInterfaces();
2030
1908
  const availableAddresses = Object.values(networkInterfaces)
@@ -2055,7 +1933,7 @@ export class Matterbridge extends EventEmitter {
2055
1933
  nodeLabel: productName,
2056
1934
  productLabel: productName,
2057
1935
  softwareVersion,
2058
- softwareVersionString, // Home app = Firmware Revision
1936
+ softwareVersionString,
2059
1937
  hardwareVersion,
2060
1938
  hardwareVersionString,
2061
1939
  uniqueId,
@@ -2151,24 +2029,6 @@ export class Matterbridge extends EventEmitter {
2151
2029
  commissioningServer.addCommandHandler('testEventTrigger', async ({ request: { enableKey, eventTrigger } }) => this.log.info(`testEventTrigger called on GeneralDiagnostic cluster: ${enableKey} ${eventTrigger}`));
2152
2030
  return commissioningServer;
2153
2031
  }
2154
- /**
2155
- * Creates a commissioning server storage context.
2156
- *
2157
- * @param pluginName - The name of the plugin.
2158
- * @param deviceName - The name of the device.
2159
- * @param deviceType - The type of the device.
2160
- * @param vendorId - The vendor ID.
2161
- * @param vendorName - The vendor name.
2162
- * @param productId - The product ID.
2163
- * @param productName - The product name.
2164
- * @param serialNumber - The serial number of the device (optional).
2165
- * @param uniqueId - The unique ID of the device (optional).
2166
- * @param softwareVersion - The software version of the device (optional).
2167
- * @param softwareVersionString - The software version string of the device (optional).
2168
- * @param hardwareVersion - The hardware version of the device (optional).
2169
- * @param hardwareVersionString - The hardware version string of the device (optional).
2170
- * @returns The storage context for the commissioning server.
2171
- */
2172
2032
  async createCommissioningServerContext(pluginName, deviceName, deviceType, vendorId, vendorName, productId, productName) {
2173
2033
  if (!this.storageManager)
2174
2034
  throw new Error('No storage manager initialized');
@@ -2196,13 +2056,6 @@ export class Matterbridge extends EventEmitter {
2196
2056
  this.log.debug(`- hardwareVersion: ${await storageContext.get('hardwareVersion')} hardwareVersionString: ${await storageContext.get('hardwareVersionString')}`);
2197
2057
  return storageContext;
2198
2058
  }
2199
- /**
2200
- * Imports the commissioning server context for a specific plugin and device.
2201
- * @param pluginName - The name of the plugin.
2202
- * @param device - The MatterbridgeDevice object representing the device.
2203
- * @returns The commissioning server context.
2204
- * @throws Error if the BasicInformationCluster is not found.
2205
- */
2206
2059
  async importCommissioningServerContext(pluginName, device) {
2207
2060
  this.log.debug(`Importing matter commissioning server storage context from device for ${plg}${pluginName}${db}`);
2208
2061
  const basic = device.getClusterServer(BasicInformationCluster);
@@ -2237,14 +2090,6 @@ export class Matterbridge extends EventEmitter {
2237
2090
  this.log.debug(`- hardwareVersion: ${await storageContext.get('hardwareVersion')} hardwareVersionString: ${await storageContext.get('hardwareVersionString')}`);
2238
2091
  return storageContext;
2239
2092
  }
2240
- /**
2241
- * Shows the commissioning server QR code for a given plugin.
2242
- * @param {CommissioningServer} commissioningServer - The commissioning server instance.
2243
- * @param {StorageContext} storageContext - The storage context instance.
2244
- * @param {NodeStorage} nodeContext - The node storage instance.
2245
- * @param {string} pluginName - The name of the plugin of Matterbridge in bridge mode.
2246
- * @returns {Promise<void>} - A promise that resolves when the QR code is shown.
2247
- */
2248
2093
  async showCommissioningQRCode(commissioningServer, storageContext, nodeContext, pluginName) {
2249
2094
  if (!commissioningServer || !storageContext || !nodeContext || !pluginName) {
2250
2095
  this.log.error(`showCommissioningQRCode error: commissioningServer: ${!commissioningServer} storageContext: ${!storageContext} nodeContext: ${!nodeContext} pluginName: ${pluginName}`);
@@ -2255,8 +2100,7 @@ export class Matterbridge extends EventEmitter {
2255
2100
  const { qrPairingCode, manualPairingCode } = commissioningServer.getPairingCode();
2256
2101
  const QrCode = new QrCodeSchema();
2257
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`);
2258
- // eslint-disable-next-line no-console
2259
- if (this.log.logLevel === "debug" /* LogLevel.DEBUG */ || this.log.logLevel === "info" /* LogLevel.INFO */)
2103
+ if (this.log.logLevel === "debug" || this.log.logLevel === "info")
2260
2104
  console.log(`${QrCode.encode(qrPairingCode)}\n`);
2261
2105
  this.log.info(`${plg}${pluginName}${nf} \n\nqrPairingCode: ${qrPairingCode} \n\nManual pairing code: ${manualPairingCode}\n`);
2262
2106
  if (pluginName === 'Matterbridge') {
@@ -2303,12 +2147,6 @@ export class Matterbridge extends EventEmitter {
2303
2147
  }
2304
2148
  this.wssSendRefreshRequired();
2305
2149
  }
2306
- /**
2307
- * Sanitizes the fabric information by converting bigint properties to string cause res.json doesn't know bigint.
2308
- *
2309
- * @param fabricInfo - The array of exposed fabric information objects.
2310
- * @returns An array of sanitized exposed fabric information objects.
2311
- */
2312
2150
  sanitizeFabricInformations(fabricInfo) {
2313
2151
  return fabricInfo.map((info) => {
2314
2152
  return {
@@ -2322,12 +2160,6 @@ export class Matterbridge extends EventEmitter {
2322
2160
  };
2323
2161
  });
2324
2162
  }
2325
- /**
2326
- * Sanitizes the session information by converting bigint properties to string.
2327
- *
2328
- * @param sessionInfo - The array of session information objects.
2329
- * @returns An array of sanitized session information objects.
2330
- */
2331
2163
  sanitizeSessionInformation(sessionInfo) {
2332
2164
  return sessionInfo
2333
2165
  .filter((session) => session.isPeerActive)
@@ -2355,12 +2187,6 @@ export class Matterbridge extends EventEmitter {
2355
2187
  };
2356
2188
  });
2357
2189
  }
2358
- /**
2359
- * Sets the reachability of a commissioning server and trigger.
2360
- *
2361
- * @param {CommissioningServer} commissioningServer - The commissioning server to set the reachability for.
2362
- * @param {boolean} reachable - The new reachability status.
2363
- */
2364
2190
  setCommissioningServerReachability(commissioningServer, reachable) {
2365
2191
  const basicInformationCluster = commissioningServer?.getRootClusterServer(BasicInformationCluster);
2366
2192
  if (basicInformationCluster && basicInformationCluster.attributes.reachable !== undefined)
@@ -2368,11 +2194,6 @@ export class Matterbridge extends EventEmitter {
2368
2194
  if (basicInformationCluster && basicInformationCluster.triggerReachableChangedEvent)
2369
2195
  basicInformationCluster.triggerReachableChangedEvent({ reachableNewValue: reachable });
2370
2196
  }
2371
- /**
2372
- * Sets the reachability of the specified matter aggregator and its bridged devices and trigger.
2373
- * @param {Aggregator} matterAggregator - The matter aggregator to set the reachability for.
2374
- * @param {boolean} reachable - A boolean indicating the reachability status to set.
2375
- */
2376
2197
  setAggregatorReachability(matterAggregator, reachable) {
2377
2198
  const basicInformationCluster = matterAggregator.getClusterServer(BasicInformationCluster);
2378
2199
  if (basicInformationCluster && basicInformationCluster.attributes.reachable !== undefined)
@@ -2385,12 +2206,6 @@ export class Matterbridge extends EventEmitter {
2385
2206
  device.getClusterServer(BridgedDeviceBasicInformationCluster)?.triggerReachableChangedEvent({ reachableNewValue: reachable });
2386
2207
  });
2387
2208
  }
2388
- /**
2389
- * Sets the reachability of a device and trigger.
2390
- *
2391
- * @param {MatterbridgeDevice} device - The device to set the reachability for.
2392
- * @param {boolean} reachable - The new reachability status of the device.
2393
- */
2394
2209
  setDeviceReachability(device, reachable) {
2395
2210
  const basicInformationCluster = device.getClusterServer(BasicInformationCluster);
2396
2211
  if (basicInformationCluster && basicInformationCluster.attributes.reachable !== undefined)
@@ -2439,10 +2254,6 @@ export class Matterbridge extends EventEmitter {
2439
2254
  }
2440
2255
  return vendorName;
2441
2256
  };
2442
- /**
2443
- * Retrieves the base registered plugins sanitized for res.json().
2444
- * @returns {BaseRegisteredPlugin[]} A promise that resolves to an array of BaseRegisteredPlugin objects.
2445
- */
2446
2257
  async getBaseRegisteredPlugins() {
2447
2258
  const baseRegisteredPlugins = [];
2448
2259
  for (const plugin of this.plugins) {
@@ -2474,36 +2285,13 @@ export class Matterbridge extends EventEmitter {
2474
2285
  }
2475
2286
  return baseRegisteredPlugins;
2476
2287
  }
2477
- /**
2478
- * Spawns a child process with the given command and arguments.
2479
- * @param {string} command - The command to execute.
2480
- * @param {string[]} args - The arguments to pass to the command (default: []).
2481
- * @returns {Promise<boolean>} A promise that resolves when the child process exits successfully, or rejects if there is an error.
2482
- */
2483
2288
  async spawnCommand(command, args = []) {
2484
- /*
2485
- npm > npm.cmd on windows
2486
- cmd.exe ['dir'] on windows
2487
- await this.spawnCommand('npm', ['install', '-g', 'matterbridge']);
2488
- process.on('unhandledRejection', (reason, promise) => {
2489
- this.log.error('Unhandled Rejection at:', promise, 'reason:', reason);
2490
- });
2491
-
2492
- spawn - [14:27:21.125] [Matterbridge:spawn]: changed 38 packages in 4s
2493
- spawn - [14:27:21.125] [Matterbridge:spawn]: 10 packages are looking for funding run `npm fund` for details
2494
- debug - [14:27:21.131] [Matterbridge]: Child process exited with code 0 and signal null
2495
- debug - [14:27:21.131] [Matterbridge]: Child process stdio streams have closed with code 0
2496
- */
2497
2289
  const cmdLine = command + ' ' + args.join(' ');
2498
2290
  if (process.platform === 'win32' && command === 'npm') {
2499
- // Must be spawn('cmd.exe', ['/c', 'npm -g install <package>']);
2500
2291
  const argstring = 'npm ' + args.join(' ');
2501
2292
  args.splice(0, args.length, '/c', argstring);
2502
2293
  command = 'cmd.exe';
2503
2294
  }
2504
- // Decide when using sudo on linux
2505
- // When you need sudo: Spawn stderr: npm error Error: EACCES: permission denied
2506
- // When you don't need sudo: Failed to start child process "npm install -g matterbridge-eve-door": spawn sudo ENOENT
2507
2295
  if (hasParameter('sudo') || (process.platform === 'linux' && command === 'npm' && !hasParameter('docker') && !hasParameter('nosudo'))) {
2508
2296
  args.unshift(command);
2509
2297
  command = 'sudo';
@@ -2561,102 +2349,55 @@ export class Matterbridge extends EventEmitter {
2561
2349
  }
2562
2350
  });
2563
2351
  }
2564
- /**
2565
- * Sends a WebSocket message to all connected clients.
2566
- *
2567
- * @param {string} level - The logger level of the message: debug info notice warn error fatal...
2568
- * @param {string} time - The time string of the message
2569
- * @param {string} name - The logger name of the message
2570
- * @param {string} message - The content of the message.
2571
- */
2572
2352
  wssSendMessage(level, time, name, message) {
2573
2353
  if (!level || !time || !name || !message)
2574
2354
  return;
2575
- // Remove ANSI escape codes from the message
2576
- // eslint-disable-next-line no-control-regex
2577
2355
  message = message.replace(/\x1B\[[0-9;]*[m|s|u|K]/g, '');
2578
- // Remove leading asterisks from the message
2579
2356
  message = message.replace(/^\*+/, '');
2580
- // Replace all occurrences of \t and \n
2581
2357
  message = message.replace(/[\t\n]/g, '');
2582
- // Remove non-printable characters
2583
- // eslint-disable-next-line no-control-regex
2584
2358
  message = message.replace(/[\x00-\x1F\x7F]/g, '');
2585
- // Replace all occurrences of \" with "
2586
2359
  message = message.replace(/\\"/g, '"');
2587
- // Define the maximum allowed length for continuous characters without a space
2588
2360
  const maxContinuousLength = 100;
2589
2361
  const keepStartLength = 20;
2590
2362
  const keepEndLength = 20;
2591
- // Split the message into words
2592
2363
  message = message
2593
2364
  .split(' ')
2594
2365
  .map((word) => {
2595
- // If the word length exceeds the max continuous length, insert spaces and truncate
2596
2366
  if (word.length > maxContinuousLength) {
2597
2367
  return word.slice(0, keepStartLength) + ' ... ' + word.slice(-keepEndLength);
2598
2368
  }
2599
2369
  return word;
2600
2370
  })
2601
2371
  .join(' ');
2602
- // Send the message to all connected clients
2603
2372
  this.webSocketServer?.clients.forEach((client) => {
2604
2373
  if (client.readyState === WebSocket.OPEN) {
2605
2374
  client.send(JSON.stringify({ id: WS_ID_LOG, src: 'Matterbridge', level, time, name, message }));
2606
2375
  }
2607
2376
  });
2608
2377
  }
2609
- /**
2610
- * Sends a need to refresh WebSocket message to all connected clients.
2611
- *
2612
- */
2613
2378
  wssSendRefreshRequired() {
2614
2379
  this.matterbridgeInformation.refreshRequired = true;
2615
- // Send the message to all connected clients
2616
2380
  this.webSocketServer?.clients.forEach((client) => {
2617
2381
  if (client.readyState === WebSocket.OPEN) {
2618
2382
  client.send(JSON.stringify({ id: WS_ID_REFRESH_NEEDED, src: 'Matterbridge', dst: 'Matterbridge', method: 'refresh_required', params: {} }));
2619
2383
  }
2620
2384
  });
2621
2385
  }
2622
- /**
2623
- * Sends a need to restart WebSocket message to all connected clients.
2624
- *
2625
- */
2626
2386
  wssSendRestartRequired() {
2627
2387
  this.matterbridgeInformation.restartRequired = true;
2628
- // Send the message to all connected clients
2629
2388
  this.webSocketServer?.clients.forEach((client) => {
2630
2389
  if (client.readyState === WebSocket.OPEN) {
2631
2390
  client.send(JSON.stringify({ id: WS_ID_RESTART_NEEDED, src: 'Matterbridge', dst: 'Matterbridge', method: 'restart_required', params: {} }));
2632
2391
  }
2633
2392
  });
2634
2393
  }
2635
- /**
2636
- * Initializes the frontend of Matterbridge.
2637
- *
2638
- * @param port The port number to run the frontend server on. Default is 8283.
2639
- */
2640
2394
  async initializeFrontend(port = 8283) {
2641
2395
  let initializeError = false;
2642
2396
  this.log.debug(`Initializing the frontend ${hasParameter('ssl') ? 'https' : 'http'} server on port ${YELLOW}${port}${db}`);
2643
- // Create the express app that serves the frontend
2644
2397
  this.expressApp = express();
2645
- // Log all requests to the server for debugging
2646
- /*
2647
- if (hasParameter('homedir')) {
2648
- this.expressApp.use((req, res, next) => {
2649
- this.log.debug(`Received request on expressApp: ${req.method} ${req.url}`);
2650
- next();
2651
- });
2652
- }
2653
- */
2654
- // Serve static files from '/static' endpoint
2655
2398
  this.expressApp.use(express.static(path.join(this.rootDirectory, 'frontend/build')));
2656
2399
  if (!hasParameter('ssl')) {
2657
- // Create an HTTP server and attach the express app
2658
2400
  this.httpServer = createServer(this.expressApp);
2659
- // Listen on the specified port
2660
2401
  if (hasParameter('ingress')) {
2661
2402
  this.httpServer.listen(port, '0.0.0.0', () => {
2662
2403
  this.log.info(`The frontend http server is listening on ${UNDERLINE}http://0.0.0.0:${port}${UNDERLINEOFF}${rs}`);
@@ -2670,7 +2411,6 @@ export class Matterbridge extends EventEmitter {
2670
2411
  this.log.info(`The frontend http server is listening on ${UNDERLINE}http://[${this.systemInformation.ipv6Address}]:${port}${UNDERLINEOFF}${rs}`);
2671
2412
  });
2672
2413
  }
2673
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
2674
2414
  this.httpServer.on('error', (error) => {
2675
2415
  this.log.error(`Frontend http server error listening on ${port}`);
2676
2416
  switch (error.code) {
@@ -2686,7 +2426,6 @@ export class Matterbridge extends EventEmitter {
2686
2426
  });
2687
2427
  }
2688
2428
  else {
2689
- // Load the SSL certificate, the private key and optionally the CA certificate
2690
2429
  let cert;
2691
2430
  try {
2692
2431
  cert = await fs.readFile(path.join(this.matterbridgeDirectory, 'certs/cert.pem'), 'utf8');
@@ -2714,9 +2453,7 @@ export class Matterbridge extends EventEmitter {
2714
2453
  this.log.info(`CA certificate file ${path.join(this.matterbridgeDirectory, 'certs/ca.pem')} not loaded: ${error}`);
2715
2454
  }
2716
2455
  const serverOptions = { cert, key, ca };
2717
- // Create an HTTPS server with the SSL certificate and private key (ca is optional) and attach the express app
2718
2456
  this.httpsServer = https.createServer(serverOptions, this.expressApp);
2719
- // Listen on the specified port
2720
2457
  if (hasParameter('ingress')) {
2721
2458
  this.httpsServer.listen(port, '0.0.0.0', () => {
2722
2459
  this.log.info(`The frontend https server is listening on ${UNDERLINE}https://0.0.0.0:${port}${UNDERLINEOFF}${rs}`);
@@ -2730,7 +2467,6 @@ export class Matterbridge extends EventEmitter {
2730
2467
  this.log.info(`The frontend https server is listening on ${UNDERLINE}https://[${this.systemInformation.ipv6Address}]:${port}${UNDERLINEOFF}${rs}`);
2731
2468
  });
2732
2469
  }
2733
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
2734
2470
  this.httpsServer.on('error', (error) => {
2735
2471
  this.log.error(`Frontend https server error listening on ${port}`);
2736
2472
  switch (error.code) {
@@ -2747,13 +2483,12 @@ export class Matterbridge extends EventEmitter {
2747
2483
  }
2748
2484
  if (initializeError)
2749
2485
  return;
2750
- // Createe a WebSocket server and attach it to the http or https server
2751
2486
  const wssPort = port;
2752
2487
  const wssHost = hasParameter('ssl') ? `wss://${this.systemInformation.ipv4Address}:${wssPort}` : `ws://${this.systemInformation.ipv4Address}:${wssPort}`;
2753
2488
  this.webSocketServer = new WebSocketServer(hasParameter('ssl') ? { server: this.httpsServer } : { server: this.httpServer });
2754
2489
  this.webSocketServer.on('connection', (ws, request) => {
2755
2490
  const clientIp = request.socket.remoteAddress;
2756
- AnsiLogger.setGlobalCallback(this.wssSendMessage.bind(this), "debug" /* LogLevel.DEBUG */);
2491
+ AnsiLogger.setGlobalCallback(this.wssSendMessage.bind(this), "debug");
2757
2492
  this.log.info(`WebSocketServer client "${clientIp}" connected to Matterbridge`);
2758
2493
  ws.on('message', (message) => {
2759
2494
  this.log.debug(`WebSocket client message: ${message}`);
@@ -2786,7 +2521,6 @@ export class Matterbridge extends EventEmitter {
2786
2521
  this.webSocketServer.on('error', (ws, error) => {
2787
2522
  this.log.error(`WebSocketServer error: ${error}`);
2788
2523
  });
2789
- // Endpoint to validate login code
2790
2524
  this.expressApp.post('/api/login', express.json(), async (req, res) => {
2791
2525
  const { password } = req.body;
2792
2526
  this.log.debug('The frontend sent /api/login', password);
@@ -2805,14 +2539,12 @@ export class Matterbridge extends EventEmitter {
2805
2539
  this.log.warn('/api/login error wrong password');
2806
2540
  res.json({ valid: false });
2807
2541
  }
2808
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
2809
2542
  }
2810
2543
  catch (error) {
2811
2544
  this.log.error('/api/login error getting password');
2812
2545
  res.json({ valid: false });
2813
2546
  }
2814
2547
  });
2815
- // Endpoint to provide settings
2816
2548
  this.expressApp.get('/api/settings', express.json(), async (req, res) => {
2817
2549
  this.log.debug('The frontend sent /api/settings');
2818
2550
  this.matterbridgeInformation.bridgeMode = this.bridgeMode;
@@ -2832,18 +2564,14 @@ export class Matterbridge extends EventEmitter {
2832
2564
  this.matterbridgeInformation.matterbridgeFabricInformations = this.matterbridgeFabricInformations;
2833
2565
  this.matterbridgeInformation.matterbridgeSessionInformations = Array.from(this.matterbridgeSessionInformations.values());
2834
2566
  this.matterbridgeInformation.profile = this.profile;
2835
- const response = { wssHost, ssl: hasParameter('ssl'), systemInformation: this.systemInformation, matterbridgeInformation: this.matterbridgeInformation };
2836
- // this.log.debug('Response:', debugStringify(response));
2567
+ const response = { systemInformation: this.systemInformation, matterbridgeInformation: this.matterbridgeInformation };
2837
2568
  res.json(response);
2838
2569
  });
2839
- // Endpoint to provide plugins
2840
2570
  this.expressApp.get('/api/plugins', async (req, res) => {
2841
2571
  this.log.debug('The frontend sent /api/plugins');
2842
2572
  const response = await this.getBaseRegisteredPlugins();
2843
- // this.log.debug('Response:', debugStringify(response));
2844
2573
  res.json(response);
2845
2574
  });
2846
- // Endpoint to provide devices
2847
2575
  this.expressApp.get('/api/devices', (req, res) => {
2848
2576
  this.log.debug('The frontend sent /api/devices');
2849
2577
  const devices = [];
@@ -2876,10 +2604,8 @@ export class Matterbridge extends EventEmitter {
2876
2604
  cluster: cluster,
2877
2605
  });
2878
2606
  });
2879
- // this.log.debug('Response:', debugStringify(data));
2880
2607
  res.json(devices);
2881
2608
  });
2882
- // Endpoint to provide the cluster servers of the devices
2883
2609
  this.expressApp.get('/api/devices_clusters/:selectedPluginName/:selectedDeviceEndpoint', (req, res) => {
2884
2610
  const selectedPluginName = req.params.selectedPluginName;
2885
2611
  const selectedDeviceEndpoint = parseInt(req.params.selectedDeviceEndpoint, 10);
@@ -2899,7 +2625,6 @@ export class Matterbridge extends EventEmitter {
2899
2625
  Object.entries(clusterServer.attributes).forEach(([key, value]) => {
2900
2626
  if (clusterServer.name === 'EveHistory')
2901
2627
  return;
2902
- // this.log.debug(`***--clusterServer: ${clusterServer.name}(${clusterServer.id}) attribute:${key}(${value.id}) ${value.isFixed} ${value.isWritable} ${value.isWritable}`);
2903
2628
  let attributeValue;
2904
2629
  try {
2905
2630
  if (typeof value.getLocal() === 'object')
@@ -2910,7 +2635,6 @@ export class Matterbridge extends EventEmitter {
2910
2635
  catch (error) {
2911
2636
  attributeValue = 'Fabric-Scoped';
2912
2637
  this.log.debug(`GetLocal value ${error} in clusterServer: ${clusterServer.name}(${clusterServer.id}) attribute: ${key}(${value.id})`);
2913
- // console.log(error);
2914
2638
  }
2915
2639
  data.push({
2916
2640
  endpoint: device.number ? device.number.toString() : '...',
@@ -2923,14 +2647,12 @@ export class Matterbridge extends EventEmitter {
2923
2647
  });
2924
2648
  });
2925
2649
  device.getChildEndpoints().forEach((childEndpoint) => {
2926
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
2927
2650
  const name = this.edge ? childEndpoint.endpoint?.id : childEndpoint.uniqueStorageKey;
2928
2651
  const clusterServers = childEndpoint.getAllClusterServers();
2929
2652
  clusterServers.forEach((clusterServer) => {
2930
2653
  Object.entries(clusterServer.attributes).forEach(([key, value]) => {
2931
2654
  if (clusterServer.name === 'EveHistory')
2932
2655
  return;
2933
- // this.log.debug(`***--clusterServer: ${clusterServer.name}(${clusterServer.id}) attribute:${key}(${value.id}) ${value.isFixed} ${value.isWritable} ${value.isWritable}`);
2934
2656
  let attributeValue;
2935
2657
  try {
2936
2658
  if (typeof value.getLocal() === 'object')
@@ -2941,7 +2663,6 @@ export class Matterbridge extends EventEmitter {
2941
2663
  catch (error) {
2942
2664
  attributeValue = 'Unavailable';
2943
2665
  this.log.debug(`GetLocal error ${error} in clusterServer: ${clusterServer.name}(${clusterServer.id}) attribute: ${key}(${value.id})`);
2944
- // console.log(error);
2945
2666
  }
2946
2667
  data.push({
2947
2668
  endpoint: (childEndpoint.number ? childEndpoint.number.toString() : '...') + (name ? ' (' + name + ')' : ''),
@@ -2958,7 +2679,6 @@ export class Matterbridge extends EventEmitter {
2958
2679
  });
2959
2680
  res.json(data);
2960
2681
  });
2961
- // Endpoint to view the log
2962
2682
  this.expressApp.get('/api/view-log', async (req, res) => {
2963
2683
  this.log.debug('The frontend sent /api/log');
2964
2684
  try {
@@ -2971,12 +2691,10 @@ export class Matterbridge extends EventEmitter {
2971
2691
  res.status(500).send('Error reading log file');
2972
2692
  }
2973
2693
  });
2974
- // Endpoint to download the matterbridge log
2975
2694
  this.expressApp.get('/api/download-mblog', async (req, res) => {
2976
2695
  this.log.debug('The frontend sent /api/download-mblog');
2977
2696
  try {
2978
2697
  await fs.access(path.join(this.matterbridgeDirectory, this.matterbrideLoggerFile), fs.constants.F_OK);
2979
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
2980
2698
  }
2981
2699
  catch (error) {
2982
2700
  fs.appendFile(path.join(this.matterbridgeDirectory, this.matterbrideLoggerFile), 'Enable the log on file in the settings to enable the file logger');
@@ -2988,12 +2706,10 @@ export class Matterbridge extends EventEmitter {
2988
2706
  }
2989
2707
  });
2990
2708
  });
2991
- // Endpoint to download the matter log
2992
2709
  this.expressApp.get('/api/download-mjlog', async (req, res) => {
2993
2710
  this.log.debug('The frontend sent /api/download-mjlog');
2994
2711
  try {
2995
2712
  await fs.access(path.join(this.matterbridgeDirectory, this.matterLoggerFile), fs.constants.F_OK);
2996
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
2997
2713
  }
2998
2714
  catch (error) {
2999
2715
  fs.appendFile(path.join(this.matterbridgeDirectory, this.matterLoggerFile), 'Enable the log on file in the settings to enable the file logger');
@@ -3005,7 +2721,6 @@ export class Matterbridge extends EventEmitter {
3005
2721
  }
3006
2722
  });
3007
2723
  });
3008
- // Endpoint to download the matter storage file
3009
2724
  this.expressApp.get('/api/download-mjstorage', (req, res) => {
3010
2725
  this.log.debug('The frontend sent /api/download-mjstorage');
3011
2726
  res.download(path.join(this.matterbridgeDirectory, this.matterStorageName), 'matterbridge.json', (error) => {
@@ -3015,7 +2730,6 @@ export class Matterbridge extends EventEmitter {
3015
2730
  }
3016
2731
  });
3017
2732
  });
3018
- // Endpoint to download the matterbridge storage directory
3019
2733
  this.expressApp.get('/api/download-mbstorage', async (req, res) => {
3020
2734
  this.log.debug('The frontend sent /api/download-mbstorage');
3021
2735
  await createZip(path.join(os.tmpdir(), `matterbridge.${this.nodeStorageName}.zip`), path.join(this.matterbridgeDirectory, this.nodeStorageName));
@@ -3026,7 +2740,6 @@ export class Matterbridge extends EventEmitter {
3026
2740
  }
3027
2741
  });
3028
2742
  });
3029
- // Endpoint to download the matterbridge plugin directory
3030
2743
  this.expressApp.get('/api/download-pluginstorage', async (req, res) => {
3031
2744
  this.log.debug('The frontend sent /api/download-pluginstorage');
3032
2745
  await createZip(path.join(os.tmpdir(), `matterbridge.pluginstorage.zip`), this.matterbridgePluginDirectory);
@@ -3037,11 +2750,9 @@ export class Matterbridge extends EventEmitter {
3037
2750
  }
3038
2751
  });
3039
2752
  });
3040
- // Endpoint to download the matterbridge plugin config files
3041
2753
  this.expressApp.get('/api/download-pluginconfig', async (req, res) => {
3042
2754
  this.log.debug('The frontend sent /api/download-pluginconfig');
3043
2755
  await createZip(path.join(os.tmpdir(), `matterbridge.pluginconfig.zip`), path.relative(process.cwd(), path.join(this.matterbridgeDirectory, '*.config.json')));
3044
- // await createZip(path.join(os.tmpdir(), `matterbridge.pluginconfig.zip`), path.relative(process.cwd(), path.join(this.matterbridgeDirectory, 'certs', '*.*')), path.relative(process.cwd(), path.join(this.matterbridgeDirectory, '*.config.json')));
3045
2756
  res.download(path.join(os.tmpdir(), `matterbridge.pluginconfig.zip`), `matterbridge.pluginconfig.zip`, (error) => {
3046
2757
  if (error) {
3047
2758
  this.log.error(`Error downloading file matterbridge.pluginstorage.zip: ${error instanceof Error ? error.message : error}`);
@@ -3049,7 +2760,6 @@ export class Matterbridge extends EventEmitter {
3049
2760
  }
3050
2761
  });
3051
2762
  });
3052
- // Endpoint to download the matterbridge plugin config files
3053
2763
  this.expressApp.get('/api/download-backup', async (req, res) => {
3054
2764
  this.log.debug('The frontend sent /api/download-backup');
3055
2765
  res.download(path.join(os.tmpdir(), `matterbridge.backup.zip`), `matterbridge.backup.zip`, (error) => {
@@ -3059,7 +2769,6 @@ export class Matterbridge extends EventEmitter {
3059
2769
  }
3060
2770
  });
3061
2771
  });
3062
- // Endpoint to receive commands
3063
2772
  this.expressApp.post('/api/command/:command/:param', express.json(), async (req, res) => {
3064
2773
  const command = req.params.command;
3065
2774
  let param = req.params.param;
@@ -3069,15 +2778,13 @@ export class Matterbridge extends EventEmitter {
3069
2778
  return;
3070
2779
  }
3071
2780
  this.log.debug(`Received frontend command: ${command}:${param}`);
3072
- // Handle the command setpassword from Settings
3073
2781
  if (command === 'setpassword') {
3074
- const password = param.slice(1, -1); // Remove the first and last characters
2782
+ const password = param.slice(1, -1);
3075
2783
  this.log.debug('setpassword', param, password);
3076
2784
  await this.nodeContext?.set('password', password);
3077
2785
  res.json({ message: 'Command received' });
3078
2786
  return;
3079
2787
  }
3080
- // Handle the command setbridgemode from Settings
3081
2788
  if (command === 'setbridgemode') {
3082
2789
  this.log.debug(`setbridgemode: ${param}`);
3083
2790
  this.wssSendRestartRequired();
@@ -3085,7 +2792,6 @@ export class Matterbridge extends EventEmitter {
3085
2792
  res.json({ message: 'Command received' });
3086
2793
  return;
3087
2794
  }
3088
- // Handle the command backup from Settings
3089
2795
  if (command === 'backup') {
3090
2796
  this.log.notice(`Prepairing the backup...`);
3091
2797
  await createZip(path.join(os.tmpdir(), `matterbridge.backup.zip`), path.join(this.matterbridgeDirectory), path.join(this.matterbridgePluginDirectory));
@@ -3093,26 +2799,25 @@ export class Matterbridge extends EventEmitter {
3093
2799
  res.json({ message: 'Command received' });
3094
2800
  return;
3095
2801
  }
3096
- // Handle the command setmbloglevel from Settings
3097
2802
  if (command === 'setmbloglevel') {
3098
2803
  this.log.debug('Matterbridge log level:', param);
3099
2804
  if (param === 'Debug') {
3100
- this.log.logLevel = "debug" /* LogLevel.DEBUG */;
2805
+ this.log.logLevel = "debug";
3101
2806
  }
3102
2807
  else if (param === 'Info') {
3103
- this.log.logLevel = "info" /* LogLevel.INFO */;
2808
+ this.log.logLevel = "info";
3104
2809
  }
3105
2810
  else if (param === 'Notice') {
3106
- this.log.logLevel = "notice" /* LogLevel.NOTICE */;
2811
+ this.log.logLevel = "notice";
3107
2812
  }
3108
2813
  else if (param === 'Warn') {
3109
- this.log.logLevel = "warn" /* LogLevel.WARN */;
2814
+ this.log.logLevel = "warn";
3110
2815
  }
3111
2816
  else if (param === 'Error') {
3112
- this.log.logLevel = "error" /* LogLevel.ERROR */;
2817
+ this.log.logLevel = "error";
3113
2818
  }
3114
2819
  else if (param === 'Fatal') {
3115
- this.log.logLevel = "fatal" /* LogLevel.FATAL */;
2820
+ this.log.logLevel = "fatal";
3116
2821
  }
3117
2822
  await this.nodeContext?.set('matterbridgeLogLevel', this.log.logLevel);
3118
2823
  MatterbridgeDevice.logLevel = this.log.logLevel;
@@ -3120,13 +2825,12 @@ export class Matterbridge extends EventEmitter {
3120
2825
  for (const plugin of this.plugins) {
3121
2826
  if (!plugin.platform || !plugin.platform.config)
3122
2827
  continue;
3123
- plugin.platform.log.logLevel = plugin.platform.config.debug ? "debug" /* LogLevel.DEBUG */ : this.log.logLevel;
3124
- await plugin.platform.onChangeLoggerLevel(plugin.platform.config.debug ? "debug" /* LogLevel.DEBUG */ : this.log.logLevel);
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);
3125
2830
  }
3126
2831
  res.json({ message: 'Command received' });
3127
2832
  return;
3128
2833
  }
3129
- // Handle the command setmbloglevel from Settings
3130
2834
  if (command === 'setmjloglevel') {
3131
2835
  this.log.debug('Matter.js log level:', param);
3132
2836
  if (param === 'Debug') {
@@ -3151,34 +2855,30 @@ export class Matterbridge extends EventEmitter {
3151
2855
  res.json({ message: 'Command received' });
3152
2856
  return;
3153
2857
  }
3154
- // Handle the command setmdnsinterface from Settings
3155
2858
  if (command === 'setmdnsinterface') {
3156
- param = param.slice(1, -1); // Remove the first and last characters *mdns*
2859
+ param = param.slice(1, -1);
3157
2860
  this.matterbridgeInformation.mattermdnsinterface = param;
3158
2861
  this.log.debug('Matter.js mdns interface:', param === '' ? 'All interfaces' : param);
3159
2862
  await this.nodeContext?.set('mattermdnsinterface', param);
3160
2863
  res.json({ message: 'Command received' });
3161
2864
  return;
3162
2865
  }
3163
- // Handle the command setipv4address from Settings
3164
2866
  if (command === 'setipv4address') {
3165
- param = param.slice(1, -1); // Remove the first and last characters *ip*
2867
+ param = param.slice(1, -1);
3166
2868
  this.matterbridgeInformation.matteripv4address = param;
3167
2869
  this.log.debug('Matter.js ipv4 address:', param === '' ? 'All ipv4 addresses' : param);
3168
2870
  await this.nodeContext?.set('matteripv4address', param);
3169
2871
  res.json({ message: 'Command received' });
3170
2872
  return;
3171
2873
  }
3172
- // Handle the command setipv6address from Settings
3173
2874
  if (command === 'setipv6address') {
3174
- param = param.slice(1, -1); // Remove the first and last characters *ip*
2875
+ param = param.slice(1, -1);
3175
2876
  this.matterbridgeInformation.matteripv6address = param;
3176
2877
  this.log.debug('Matter.js ipv6 address:', param === '' ? 'All ipv6 addresses' : param);
3177
2878
  await this.nodeContext?.set('matteripv6address', param);
3178
2879
  res.json({ message: 'Command received' });
3179
2880
  return;
3180
2881
  }
3181
- // Handle the command setmatterport from Settings
3182
2882
  if (command === 'setmatterport') {
3183
2883
  const port = Math.min(Math.max(parseInt(param), 5540), 5560);
3184
2884
  this.matterbridgeInformation.matterPort = port;
@@ -3187,7 +2887,6 @@ export class Matterbridge extends EventEmitter {
3187
2887
  res.json({ message: 'Command received' });
3188
2888
  return;
3189
2889
  }
3190
- // Handle the command setmatterdiscriminator from Settings
3191
2890
  if (command === 'setmatterdiscriminator') {
3192
2891
  const discriminator = Math.min(Math.max(parseInt(param), 1000), 4095);
3193
2892
  this.matterbridgeInformation.matterDiscriminator = discriminator;
@@ -3196,7 +2895,6 @@ export class Matterbridge extends EventEmitter {
3196
2895
  res.json({ message: 'Command received' });
3197
2896
  return;
3198
2897
  }
3199
- // Handle the command setmatterpasscode from Settings
3200
2898
  if (command === 'setmatterpasscode') {
3201
2899
  const passcode = Math.min(Math.max(parseInt(param), 10000000), 90000000);
3202
2900
  this.matterbridgeInformation.matterPasscode = passcode;
@@ -3205,20 +2903,17 @@ export class Matterbridge extends EventEmitter {
3205
2903
  res.json({ message: 'Command received' });
3206
2904
  return;
3207
2905
  }
3208
- // Handle the command setmbloglevel from Settings
3209
2906
  if (command === 'setmblogfile') {
3210
2907
  this.log.debug('Matterbridge file log:', param);
3211
2908
  this.matterbridgeInformation.fileLogger = param === 'true';
3212
2909
  await this.nodeContext?.set('matterbridgeFileLog', param === 'true');
3213
- // Create the file logger for matterbridge
3214
2910
  if (param === 'true')
3215
- AnsiLogger.setGlobalLogfile(path.join(this.matterbridgeDirectory, this.matterbrideLoggerFile), "debug" /* LogLevel.DEBUG */, true);
2911
+ AnsiLogger.setGlobalLogfile(path.join(this.matterbridgeDirectory, this.matterbrideLoggerFile), "debug", true);
3216
2912
  else
3217
2913
  AnsiLogger.setGlobalLogfile(undefined);
3218
2914
  res.json({ message: 'Command received' });
3219
2915
  return;
3220
2916
  }
3221
- // Handle the command setmbloglevel from Settings
3222
2917
  if (command === 'setmjlogfile') {
3223
2918
  this.log.debug('Matter file log:', param);
3224
2919
  this.matterbridgeInformation.matterFileLogger = param === 'true';
@@ -3245,43 +2940,36 @@ export class Matterbridge extends EventEmitter {
3245
2940
  res.json({ message: 'Command received' });
3246
2941
  return;
3247
2942
  }
3248
- // Handle the command unregister from Settings
3249
2943
  if (command === 'unregister') {
3250
2944
  await this.unregisterAndShutdownProcess();
3251
2945
  res.json({ message: 'Command received' });
3252
2946
  return;
3253
2947
  }
3254
- // Handle the command reset from Settings
3255
2948
  if (command === 'reset') {
3256
2949
  await this.shutdownProcessAndReset();
3257
2950
  res.json({ message: 'Command received' });
3258
2951
  return;
3259
2952
  }
3260
- // Handle the command factoryreset from Settings
3261
2953
  if (command === 'factoryreset') {
3262
2954
  await this.shutdownProcessAndFactoryReset();
3263
2955
  res.json({ message: 'Command received' });
3264
2956
  return;
3265
2957
  }
3266
- // Handle the command shutdown from Header
3267
2958
  if (command === 'shutdown') {
3268
2959
  await this.shutdownProcess();
3269
2960
  res.json({ message: 'Command received' });
3270
2961
  return;
3271
2962
  }
3272
- // Handle the command restart from Header
3273
2963
  if (command === 'restart') {
3274
2964
  await this.restartProcess();
3275
2965
  res.json({ message: 'Command received' });
3276
2966
  return;
3277
2967
  }
3278
- // Handle the command update from Header
3279
2968
  if (command === 'update') {
3280
2969
  this.log.info('Updating matterbridge...');
3281
2970
  try {
3282
2971
  await this.spawnCommand('npm', ['install', '-g', 'matterbridge', '--omit=dev', '--verbose']);
3283
2972
  this.log.info('Matterbridge has been updated. Full restart required.');
3284
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
3285
2973
  }
3286
2974
  catch (error) {
3287
2975
  this.log.error('Error updating matterbridge');
@@ -3291,11 +2979,9 @@ export class Matterbridge extends EventEmitter {
3291
2979
  res.json({ message: 'Command received' });
3292
2980
  return;
3293
2981
  }
3294
- // Handle the command saveconfig from Home
3295
2982
  if (command === 'saveconfig') {
3296
2983
  param = param.replace(/\*/g, '\\');
3297
2984
  this.log.info(`Saving config for plugin ${plg}${param}${nf}...`);
3298
- // console.log('Req.body:', JSON.stringify(req.body, null, 2));
3299
2985
  if (!this.plugins.has(param)) {
3300
2986
  this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
3301
2987
  }
@@ -3309,39 +2995,33 @@ export class Matterbridge extends EventEmitter {
3309
2995
  res.json({ message: 'Command received' });
3310
2996
  return;
3311
2997
  }
3312
- // Handle the command installplugin from Home
3313
2998
  if (command === 'installplugin') {
3314
2999
  param = param.replace(/\*/g, '\\');
3315
3000
  this.log.info(`Installing plugin ${plg}${param}${nf}...`);
3316
3001
  try {
3317
3002
  await this.spawnCommand('npm', ['install', '-g', param, '--omit=dev', '--verbose']);
3318
3003
  this.log.info(`Plugin ${plg}${param}${nf} installed. Full restart required.`);
3319
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
3320
3004
  }
3321
3005
  catch (error) {
3322
3006
  this.log.error(`Error installing plugin ${plg}${param}${er}`);
3323
3007
  }
3324
3008
  this.wssSendRestartRequired();
3325
3009
  param = param.split('@')[0];
3326
- // Also add the plugin to matterbridge so no return!
3327
3010
  if (param === 'matterbridge') {
3328
- // If we used the command installplugin to install a dev or a specific version of matterbridge we don't want to add it to matterbridge
3329
3011
  res.json({ message: 'Command received' });
3330
3012
  return;
3331
3013
  }
3332
3014
  }
3333
- // Handle the command addplugin from Home
3334
3015
  if (command === 'addplugin' || command === 'installplugin') {
3335
3016
  param = param.replace(/\*/g, '\\');
3336
3017
  const plugin = await this.plugins.add(param);
3337
3018
  if (plugin) {
3338
- 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);
3339
3020
  }
3340
3021
  res.json({ message: 'Command received' });
3341
3022
  this.wssSendRefreshRequired();
3342
3023
  return;
3343
3024
  }
3344
- // Handle the command removeplugin from Home
3345
3025
  if (command === 'removeplugin') {
3346
3026
  if (!this.plugins.has(param)) {
3347
3027
  this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
@@ -3355,7 +3035,6 @@ export class Matterbridge extends EventEmitter {
3355
3035
  this.wssSendRefreshRequired();
3356
3036
  return;
3357
3037
  }
3358
- // Handle the command enableplugin from Home
3359
3038
  if (command === 'enableplugin') {
3360
3039
  if (!this.plugins.has(param)) {
3361
3040
  this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
@@ -3373,14 +3052,13 @@ export class Matterbridge extends EventEmitter {
3373
3052
  plugin.registeredDevices = undefined;
3374
3053
  plugin.addedDevices = undefined;
3375
3054
  await this.plugins.enable(param);
3376
- 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);
3377
3056
  }
3378
3057
  }
3379
3058
  res.json({ message: 'Command received' });
3380
3059
  this.wssSendRefreshRequired();
3381
3060
  return;
3382
3061
  }
3383
- // Handle the command disableplugin from Home
3384
3062
  if (command === 'disableplugin') {
3385
3063
  if (!this.plugins.has(param)) {
3386
3064
  this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
@@ -3397,7 +3075,6 @@ export class Matterbridge extends EventEmitter {
3397
3075
  return;
3398
3076
  }
3399
3077
  });
3400
- // Fallback for routing (must be the last route)
3401
3078
  this.expressApp.get('*', (req, res) => {
3402
3079
  this.log.debug('The frontend sent:', req.url);
3403
3080
  this.log.debug('Response send file:', path.join(this.rootDirectory, 'frontend/build/index.html'));
@@ -3405,11 +3082,6 @@ export class Matterbridge extends EventEmitter {
3405
3082
  });
3406
3083
  this.log.debug(`Frontend initialized on port ${YELLOW}${port}${db} static ${UNDERLINE}${path.join(this.rootDirectory, 'frontend/build')}${UNDERLINEOFF}${rs}`);
3407
3084
  }
3408
- /**
3409
- * Retrieves the cluster text description from a given device.
3410
- * @param {MatterbridgeDevice} device - The MatterbridgeDevice object.
3411
- * @returns {string} The attributes description of the cluster servers in the device.
3412
- */
3413
3085
  getClusterTextFromDevice(device) {
3414
3086
  const stringifyUserLabel = (endpoint) => {
3415
3087
  const labelList = endpoint.getClusterServer(UserLabelCluster)?.attributes.labelList.getLocal();
@@ -3432,11 +3104,9 @@ export class Matterbridge extends EventEmitter {
3432
3104
  return '';
3433
3105
  };
3434
3106
  let attributes = '';
3435
- // this.log.debug(`***getClusterTextFromDevice: ${device.deviceName} (${device.name})`);
3436
3107
  const clusterServers = device.getAllClusterServers();
3437
3108
  clusterServers.forEach((clusterServer) => {
3438
3109
  try {
3439
- // this.log.debug(`**--clusterServer: ${clusterServer.id} (${clusterServer.name})`);
3440
3110
  if (clusterServer.name === 'OnOff')
3441
3111
  attributes += `OnOff: ${clusterServer.attributes.onOff.getLocal()} `;
3442
3112
  if (clusterServer.name === 'Switch')
@@ -3487,30 +3157,18 @@ export class Matterbridge extends EventEmitter {
3487
3157
  attributes += `${stringifyFixedLabel(device)} `;
3488
3158
  if (clusterServer.name === 'UserLabel')
3489
3159
  attributes += `${stringifyUserLabel(device)} `;
3490
- // this.log.debug(`*--clusterServer: ${clusterServer.id} (${clusterServer.name})`);
3491
3160
  }
3492
3161
  catch (error) {
3493
3162
  this.log.error(`getClusterTextFromDevice with ${clusterServer.name} error: ${error}`);
3494
3163
  }
3495
3164
  });
3496
- // this.log.debug(`*getClusterTextFromDevice: ${device.deviceName} (${device.name})`);
3497
3165
  return attributes;
3498
3166
  }
3499
- /**
3500
- * Initializes the Matterbridge instance as extension for zigbee2mqtt.
3501
- * @deprecated This method is deprecated and will be removed in a future version.
3502
- *
3503
- * @returns A Promise that resolves when the initialization is complete.
3504
- */
3505
3167
  async startExtension(dataPath, extensionVersion, port = 5540) {
3506
- // Set the bridge mode
3507
3168
  this.bridgeMode = 'bridge';
3508
- // Set the first port to use
3509
3169
  this.port = port;
3510
- // Set Matterbridge logger
3511
- 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" });
3512
3171
  this.log.debug('Matterbridge extension is starting...');
3513
- // Initialize NodeStorage
3514
3172
  this.matterbridgeDirectory = dataPath;
3515
3173
  this.log.debug('Creating node storage manager dir: ' + path.join(this.matterbridgeDirectory, 'node_storage'));
3516
3174
  this.nodeStorage = new NodeStorageManager({ dir: path.join(this.matterbridgeDirectory, 'node_storage'), logging: false });
@@ -3529,13 +3187,10 @@ export class Matterbridge extends EventEmitter {
3529
3187
  };
3530
3188
  this.plugins.set(plugin);
3531
3189
  this.plugins.saveToStorage();
3532
- // Log system info and create .matterbridge directory
3533
3190
  await this.logNodeAndSystemInfo();
3534
3191
  this.matterbridgeDirectory = dataPath;
3535
- // Set matter.js logger level and format
3536
3192
  Logger.defaultLogLevel = MatterLogLevel.INFO;
3537
3193
  Logger.format = MatterLogFormat.ANSI;
3538
- // Start the storage and create matterbridgeContext
3539
3194
  await this.startMatterStorage('json', path.join(this.matterbridgeDirectory, this.matterStorageName));
3540
3195
  if (!this.storageManager)
3541
3196
  return false;
@@ -3545,7 +3200,7 @@ export class Matterbridge extends EventEmitter {
3545
3200
  await this.matterbridgeContext.set('softwareVersion', 1);
3546
3201
  await this.matterbridgeContext.set('softwareVersionString', this.matterbridgeVersion);
3547
3202
  await this.matterbridgeContext.set('hardwareVersion', 1);
3548
- await this.matterbridgeContext.set('hardwareVersionString', extensionVersion); // Update with the extension version
3203
+ await this.matterbridgeContext.set('hardwareVersionString', extensionVersion);
3549
3204
  this.matterServer = this.createMatterServer(this.storageManager);
3550
3205
  this.log.debug(`Creating commissioning server for ${plg}Matterbridge${db}`);
3551
3206
  this.commissioningServer = await this.createCommisioningServer(this.matterbridgeContext, 'Matterbridge');
@@ -3558,7 +3213,6 @@ export class Matterbridge extends EventEmitter {
3558
3213
  await this.startMatterServer();
3559
3214
  this.log.info('Matter server started');
3560
3215
  await this.showCommissioningQRCode(this.commissioningServer, this.matterbridgeContext, this.nodeContext, 'Matterbridge');
3561
- // Set reachability to true and trigger event after 60 seconds
3562
3216
  setTimeout(() => {
3563
3217
  this.log.info(`Setting reachability to true for ${plg}Matterbridge${db}`);
3564
3218
  if (this.commissioningServer)
@@ -3568,31 +3222,14 @@ export class Matterbridge extends EventEmitter {
3568
3222
  }, 60 * 1000);
3569
3223
  return this.commissioningServer.isCommissioned();
3570
3224
  }
3571
- /**
3572
- * Close the Matterbridge instance as extension for zigbee2mqtt.
3573
- * @deprecated This method is deprecated and will be removed in a future version.
3574
- *
3575
- * @returns A Promise that resolves when the initialization is complete.
3576
- */
3577
3225
  async stopExtension() {
3578
- // Closing matter
3579
3226
  await this.stopMatterServer();
3580
- // Clearing the session manager
3581
- // this.matterbridgeContext?.createContext('SessionManager').clear();
3582
- // Closing storage
3583
3227
  await this.stopMatterStorage();
3584
3228
  this.log.info('Matter server stopped');
3585
3229
  }
3586
- /**
3587
- * Checks if the extension is commissioned.
3588
- * @deprecated This method is deprecated and will be removed in a future version.
3589
- *
3590
- * @returns {boolean} Returns true if the extension is commissioned, false otherwise.
3591
- */
3592
3230
  isExtensionCommissioned() {
3593
3231
  if (!this.commissioningServer)
3594
3232
  return false;
3595
3233
  return this.commissioningServer.isCommissioned();
3596
3234
  }
3597
3235
  }
3598
- //# sourceMappingURL=matterbridge.js.map