matterbridge 2.0.0 → 2.1.0-dev.10

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 (103) hide show
  1. package/CHANGELOG.md +26 -4
  2. package/README.md +1 -1
  3. package/dist/cli.js +0 -26
  4. package/dist/cluster/export.js +0 -2
  5. package/dist/defaultConfigSchema.js +0 -23
  6. package/dist/deviceManager.js +1 -26
  7. package/dist/frontend.js +143 -313
  8. package/dist/index.js +2 -30
  9. package/dist/logger/export.js +0 -1
  10. package/dist/matter/behaviors.js +1 -0
  11. package/dist/matter/clusters.js +1 -0
  12. package/dist/matter/devices.js +1 -0
  13. package/dist/matter/endpoints.js +1 -0
  14. package/dist/matter/export.js +1 -11
  15. package/dist/matter/types.js +2 -0
  16. package/dist/matterbridge.js +77 -715
  17. package/dist/matterbridgeAccessoryPlatform.js +0 -33
  18. package/dist/matterbridgeBehaviors.js +38 -38
  19. package/dist/matterbridgeDeviceTypes.js +11 -112
  20. package/dist/matterbridgeDynamicPlatform.js +0 -33
  21. package/dist/matterbridgeEndpoint.js +664 -2563
  22. package/dist/matterbridgeEndpointHelpers.js +513 -0
  23. package/dist/matterbridgePlatform.js +5 -125
  24. package/dist/matterbridgeTypes.js +0 -28
  25. package/dist/pluginManager.js +3 -240
  26. package/dist/storage/export.js +0 -1
  27. package/dist/utils/colorUtils.js +2 -205
  28. package/dist/utils/export.js +0 -1
  29. package/dist/utils/utils.js +7 -251
  30. package/frontend/build/asset-manifest.json +3 -3
  31. package/frontend/build/index.html +1 -1
  32. package/frontend/build/static/js/{main.6df4ebe4.js → main.26dbf9b9.js} +3 -3
  33. package/frontend/build/static/js/{main.6df4ebe4.js.map → main.26dbf9b9.js.map} +1 -1
  34. package/npm-shrinkwrap.json +86 -78
  35. package/package.json +22 -4
  36. package/dist/cli.d.ts +0 -25
  37. package/dist/cli.d.ts.map +0 -1
  38. package/dist/cli.js.map +0 -1
  39. package/dist/cluster/export.d.ts +0 -2
  40. package/dist/cluster/export.d.ts.map +0 -1
  41. package/dist/cluster/export.js.map +0 -1
  42. package/dist/defaultConfigSchema.d.ts +0 -27
  43. package/dist/defaultConfigSchema.d.ts.map +0 -1
  44. package/dist/defaultConfigSchema.js.map +0 -1
  45. package/dist/deviceManager.d.ts +0 -46
  46. package/dist/deviceManager.d.ts.map +0 -1
  47. package/dist/deviceManager.js.map +0 -1
  48. package/dist/frontend.d.ts +0 -98
  49. package/dist/frontend.d.ts.map +0 -1
  50. package/dist/frontend.js.map +0 -1
  51. package/dist/index.d.ts +0 -34
  52. package/dist/index.d.ts.map +0 -1
  53. package/dist/index.js.map +0 -1
  54. package/dist/logger/export.d.ts +0 -2
  55. package/dist/logger/export.d.ts.map +0 -1
  56. package/dist/logger/export.js.map +0 -1
  57. package/dist/matter/export.d.ts +0 -10
  58. package/dist/matter/export.d.ts.map +0 -1
  59. package/dist/matter/export.js.map +0 -1
  60. package/dist/matterbridge.d.ts +0 -356
  61. package/dist/matterbridge.d.ts.map +0 -1
  62. package/dist/matterbridge.js.map +0 -1
  63. package/dist/matterbridgeAccessoryPlatform.d.ts +0 -39
  64. package/dist/matterbridgeAccessoryPlatform.d.ts.map +0 -1
  65. package/dist/matterbridgeAccessoryPlatform.js.map +0 -1
  66. package/dist/matterbridgeBehaviors.d.ts +0 -963
  67. package/dist/matterbridgeBehaviors.d.ts.map +0 -1
  68. package/dist/matterbridgeBehaviors.js.map +0 -1
  69. package/dist/matterbridgeDeviceTypes.d.ts +0 -177
  70. package/dist/matterbridgeDeviceTypes.d.ts.map +0 -1
  71. package/dist/matterbridgeDeviceTypes.js.map +0 -1
  72. package/dist/matterbridgeDynamicPlatform.d.ts +0 -39
  73. package/dist/matterbridgeDynamicPlatform.d.ts.map +0 -1
  74. package/dist/matterbridgeDynamicPlatform.js.map +0 -1
  75. package/dist/matterbridgeEndpoint.d.ts +0 -10254
  76. package/dist/matterbridgeEndpoint.d.ts.map +0 -1
  77. package/dist/matterbridgeEndpoint.js.map +0 -1
  78. package/dist/matterbridgeEndpointDefault.d.ts +0 -2
  79. package/dist/matterbridgeEndpointDefault.d.ts.map +0 -1
  80. package/dist/matterbridgeEndpointDefault.js +0 -159
  81. package/dist/matterbridgeEndpointDefault.js.map +0 -1
  82. package/dist/matterbridgePlatform.d.ts +0 -164
  83. package/dist/matterbridgePlatform.d.ts.map +0 -1
  84. package/dist/matterbridgePlatform.js.map +0 -1
  85. package/dist/matterbridgeTypes.d.ts +0 -167
  86. package/dist/matterbridgeTypes.d.ts.map +0 -1
  87. package/dist/matterbridgeTypes.js.map +0 -1
  88. package/dist/pluginManager.d.ts +0 -238
  89. package/dist/pluginManager.d.ts.map +0 -1
  90. package/dist/pluginManager.js.map +0 -1
  91. package/dist/storage/export.d.ts +0 -2
  92. package/dist/storage/export.d.ts.map +0 -1
  93. package/dist/storage/export.js.map +0 -1
  94. package/dist/utils/colorUtils.d.ts +0 -61
  95. package/dist/utils/colorUtils.d.ts.map +0 -1
  96. package/dist/utils/colorUtils.js.map +0 -1
  97. package/dist/utils/export.d.ts +0 -3
  98. package/dist/utils/export.d.ts.map +0 -1
  99. package/dist/utils/export.js.map +0 -1
  100. package/dist/utils/utils.d.ts +0 -221
  101. package/dist/utils/utils.d.ts.map +0 -1
  102. package/dist/utils/utils.js.map +0 -1
  103. /package/frontend/build/static/js/{main.6df4ebe4.js.LICENSE.txt → main.26dbf9b9.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';
@@ -28,27 +5,20 @@ import EventEmitter from 'events';
28
5
  import os from 'os';
29
6
  import path from 'path';
30
7
  import { randomBytes } from 'crypto';
31
- // NodeStorage and AnsiLogger modules
32
8
  import { NodeStorageManager } from './storage/export.js';
33
9
  import { AnsiLogger, UNDERLINE, UNDERLINEOFF, YELLOW, db, debugStringify, BRIGHT, RESET, er, nf, rs, wr, RED, GREEN, zb, CYAN, nt } from './logger/export.js';
34
- // Matterbridge
35
- import { logInterfaces, wait, waiter, copyDirectory, getParameter, getIntParameter, hasParameter } from './utils/utils.js';
10
+ import { logInterfaces, copyDirectory, getParameter, getIntParameter, hasParameter } from './utils/utils.js';
36
11
  import { PluginManager } from './pluginManager.js';
37
12
  import { DeviceManager } from './deviceManager.js';
38
13
  import { MatterbridgeEndpoint } from './matterbridgeEndpoint.js';
39
14
  import { bridge } from './matterbridgeDeviceTypes.js';
40
15
  import { Frontend } from './frontend.js';
41
- // @matter
42
16
  import { DeviceTypeId, Endpoint as EndpointNode, Logger, LogLevel as MatterLogLevel, LogFormat as MatterLogFormat, VendorId, StorageService, Environment, ServerNode } from '@matter/main';
43
- import { FabricAction, PaseClient } from '@matter/main/protocol';
17
+ import { DeviceCommissioner, FabricAction, MdnsService, PaseClient } from '@matter/main/protocol';
44
18
  import { AggregatorEndpoint } from '@matter/main/endpoints';
45
- // Default colors
46
19
  const plg = '\u001B[38;5;33m';
47
20
  const dev = '\u001B[38;5;79m';
48
21
  const typ = '\u001B[38;5;207m';
49
- /**
50
- * Represents the Matterbridge application.
51
- */
52
22
  export class Matterbridge extends EventEmitter {
53
23
  systemInformation = {
54
24
  interfaceName: '',
@@ -83,7 +53,7 @@ export class Matterbridge extends EventEmitter {
83
53
  restartMode: '',
84
54
  readOnly: hasParameter('readonly'),
85
55
  profile: getParameter('profile'),
86
- loggerLevel: "info" /* LogLevel.INFO */,
56
+ loggerLevel: "info",
87
57
  fileLogger: false,
88
58
  matterLoggerLevel: MatterLogLevel.INFO,
89
59
  matterFileLogger: false,
@@ -105,9 +75,9 @@ export class Matterbridge extends EventEmitter {
105
75
  matterbridgeLatestVersion = '';
106
76
  matterbridgeQrPairingCode = undefined;
107
77
  matterbridgeManualPairingCode = undefined;
108
- matterbridgeFabricInformations = [];
109
- matterbridgeSessionInformations = [];
110
- matterbridgePaired = false;
78
+ matterbridgeFabricInformations = undefined;
79
+ matterbridgeSessionInformations = undefined;
80
+ matterbridgePaired = undefined;
111
81
  bridgeMode = '';
112
82
  restartMode = '';
113
83
  profile = getParameter('profile');
@@ -118,11 +88,9 @@ export class Matterbridge extends EventEmitter {
118
88
  plugins;
119
89
  devices;
120
90
  frontend = new Frontend(this);
121
- // Matterbridge storage
122
91
  nodeStorage;
123
92
  nodeContext;
124
93
  nodeStorageName = 'storage' + (getParameter('profile') ? '.' + getParameter('profile') : '');
125
- // Cleanup
126
94
  hasCleanupStarted = false;
127
95
  initialized = false;
128
96
  execRunningCount = 0;
@@ -134,57 +102,34 @@ export class Matterbridge extends EventEmitter {
134
102
  sigtermHandler;
135
103
  exceptionHandler;
136
104
  rejectionHandler;
137
- // Matter environment
138
105
  environment = Environment.default;
139
- // Matter storage
140
106
  matterStorageName = 'matterstorage' + (getParameter('profile') ? '.' + getParameter('profile') : '');
141
107
  matterStorageService;
142
108
  matterStorageManager;
143
109
  matterbridgeContext;
144
110
  mattercontrollerContext;
145
- // Matter parameters
146
- mdnsInterface; // matter server node mdnsInterface: e.g. 'eth0' or 'wlan0' or 'WiFi'
147
- ipv4address; // matter server node listeningAddressIpv4
148
- ipv6address; // matter server node listeningAddressIpv6
149
- port; // first server node port
150
- passcode; // first server node passcode
151
- discriminator; // first server node discriminator
111
+ mdnsInterface;
112
+ ipv4address;
113
+ ipv6address;
114
+ port;
115
+ passcode;
116
+ discriminator;
152
117
  serverNode;
153
118
  aggregatorNode;
154
119
  aggregatorVendorId = VendorId(getIntParameter('vendorId') ?? 0xfff1);
155
120
  aggregatorProductId = getIntParameter('productId') ?? 0x8000;
156
121
  static instance;
157
- // We load asyncronously so is private
158
122
  constructor() {
159
123
  super();
160
124
  }
161
- /**
162
- * Retrieves the list of Matterbridge devices.
163
- * @returns {MatterbridgeEndpoint[]} An array of MatterbridgeDevice objects.
164
- */
165
125
  getDevices() {
166
126
  return this.devices.array();
167
127
  }
168
- /**
169
- * Retrieves the list of registered plugins.
170
- * @returns {RegisteredPlugin[]} An array of RegisteredPlugin objects.
171
- */
172
128
  getPlugins() {
173
129
  return this.plugins.array();
174
130
  }
175
- /** ***********************************************************************************************************************************/
176
- /** loadInstance() and cleanup() methods */
177
- /** ***********************************************************************************************************************************/
178
- /**
179
- * Loads an instance of the Matterbridge class.
180
- * If an instance already exists, return that instance.
181
- *
182
- * @param initialize - Whether to initialize the Matterbridge instance after loading.
183
- * @returns The loaded Matterbridge instance.
184
- */
185
131
  static async loadInstance(initialize = false) {
186
132
  if (!Matterbridge.instance) {
187
- // eslint-disable-next-line no-console
188
133
  if (hasParameter('debug'))
189
134
  console.log(GREEN + 'Creating a new instance of Matterbridge.', initialize ? 'Initializing...' : 'Not initializing...', rs);
190
135
  Matterbridge.instance = new Matterbridge();
@@ -193,80 +138,48 @@ export class Matterbridge extends EventEmitter {
193
138
  }
194
139
  return Matterbridge.instance;
195
140
  }
196
- /**
197
- * Call cleanup().
198
- * @deprecated This method is deprecated and is only used for jest tests.
199
- *
200
- */
201
141
  async destroyInstance() {
202
142
  await this.cleanup('destroying instance...', false);
203
- await waiter('destroying instance...', () => {
204
- return this.initialized === false && this.execRunningCount <= 0 ? true : false;
205
- }, false, 60000, 100, false);
206
- await wait(1000, 'Wait for the global node_modules and matterbridge version', false);
207
143
  }
208
- /**
209
- * Initializes the Matterbridge application.
210
- *
211
- * @remarks
212
- * This method performs the necessary setup and initialization steps for the Matterbridge application.
213
- * It displays the help information if the 'help' parameter is provided, sets up the logger, checks the
214
- * node version, registers signal handlers, initializes storage, and parses the command line.
215
- *
216
- * @returns A Promise that resolves when the initialization is complete.
217
- */
218
144
  async initialize() {
219
- // Set the restart mode
220
145
  if (hasParameter('service'))
221
146
  this.restartMode = 'service';
222
147
  if (hasParameter('docker'))
223
148
  this.restartMode = 'docker';
224
- // Set the matterbridge directory
225
149
  this.homeDirectory = getParameter('homedir') ?? os.homedir();
226
150
  this.matterbridgeDirectory = path.join(this.homeDirectory, '.matterbridge');
227
- // Setup matter environment
228
151
  this.environment.vars.set('log.level', MatterLogLevel.INFO);
229
152
  this.environment.vars.set('log.format', MatterLogFormat.ANSI);
230
153
  this.environment.vars.set('path.root', path.join(this.matterbridgeDirectory, this.matterStorageName));
231
154
  this.environment.vars.set('runtime.signals', false);
232
155
  this.environment.vars.set('runtime.exitcode', false);
233
- // Create matterbridge logger
234
- this.log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: hasParameter('debug') ? "debug" /* LogLevel.DEBUG */ : "info" /* LogLevel.INFO */ });
235
- // Register process handlers
156
+ this.log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4, logLevel: hasParameter('debug') ? "debug" : "info" });
236
157
  this.registerProcessHandlers();
237
- // Initialize nodeStorage and nodeContext
238
158
  try {
239
159
  this.log.debug(`Creating node storage manager: ${CYAN}${this.nodeStorageName}${db}`);
240
160
  this.nodeStorage = new NodeStorageManager({ dir: path.join(this.matterbridgeDirectory, this.nodeStorageName), writeQueue: false, expiredInterval: undefined, logging: false });
241
161
  this.log.debug('Creating node storage context for matterbridge');
242
162
  this.nodeContext = await this.nodeStorage.createStorage('matterbridge');
243
- // TODO: Remove this code when node-persist-manager is updated
244
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
245
163
  const keys = (await this.nodeStorage?.storage.keys());
246
164
  for (const key of keys) {
247
165
  this.log.debug(`Checking node storage manager key: ${CYAN}${key}${db}`);
248
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
249
166
  await this.nodeStorage?.storage.get(key);
250
167
  }
251
168
  const storages = await this.nodeStorage.getStorageNames();
252
169
  for (const storage of storages) {
253
170
  this.log.debug(`Checking storage: ${CYAN}${storage}${db}`);
254
171
  const nodeContext = await this.nodeStorage?.createStorage(storage);
255
- // TODO: Remove this code when node-persist-manager is updated
256
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
257
172
  const keys = (await nodeContext?.storage.keys());
258
173
  keys.forEach(async (key) => {
259
174
  this.log.debug(`Checking key: ${CYAN}${storage}:${key}${db}`);
260
175
  await nodeContext?.get(key);
261
176
  });
262
177
  }
263
- // Creating a backup of the node storage since it is not corrupted
264
178
  this.log.debug('Creating node storage backup...');
265
179
  await copyDirectory(path.join(this.matterbridgeDirectory, this.nodeStorageName), path.join(this.matterbridgeDirectory, this.nodeStorageName + '.backup'));
266
180
  this.log.debug('Created node storage backup');
267
181
  }
268
182
  catch (error) {
269
- // Restoring the backup of the node storage since it is corrupted
270
183
  this.log.error(`Error creating node storage manager and context: ${error instanceof Error ? error.message : error}`);
271
184
  if (hasParameter('norestore')) {
272
185
  this.log.fatal(`The matterbridge node storage is corrupted. Parameter -norestore found: exiting...`);
@@ -281,51 +194,45 @@ export class Matterbridge extends EventEmitter {
281
194
  this.log.fatal('Fatal error creating node storage manager and context for matterbridge');
282
195
  throw new Error('Fatal error creating node storage manager and context for matterbridge');
283
196
  }
284
- // Set the first port to use for the commissioning server (will be incremented in childbridge mode)
285
197
  this.port = getIntParameter('port') ?? (await this.nodeContext.get('matterport', 5540)) ?? 5540;
286
- // Set the first passcode to use for the commissioning server (will be incremented in childbridge mode)
287
198
  this.passcode = getIntParameter('passcode') ?? (await this.nodeContext.get('matterpasscode')) ?? PaseClient.generateRandomPasscode();
288
- // Set the first discriminator to use for the commissioning server (will be incremented in childbridge mode)
289
199
  this.discriminator = getIntParameter('discriminator') ?? (await this.nodeContext.get('matterdiscriminator')) ?? PaseClient.generateRandomDiscriminator();
290
200
  this.log.debug(`Initializing commissioning server for Matterbridge... on port ${this.port} with passcode ${this.passcode} and discriminator ${this.discriminator}`);
291
- // Set matterbridge logger level (context: matterbridgeLogLevel)
292
201
  if (hasParameter('logger')) {
293
202
  const level = getParameter('logger');
294
203
  if (level === 'debug') {
295
- this.log.logLevel = "debug" /* LogLevel.DEBUG */;
204
+ this.log.logLevel = "debug";
296
205
  }
297
206
  else if (level === 'info') {
298
- this.log.logLevel = "info" /* LogLevel.INFO */;
207
+ this.log.logLevel = "info";
299
208
  }
300
209
  else if (level === 'notice') {
301
- this.log.logLevel = "notice" /* LogLevel.NOTICE */;
210
+ this.log.logLevel = "notice";
302
211
  }
303
212
  else if (level === 'warn') {
304
- this.log.logLevel = "warn" /* LogLevel.WARN */;
213
+ this.log.logLevel = "warn";
305
214
  }
306
215
  else if (level === 'error') {
307
- this.log.logLevel = "error" /* LogLevel.ERROR */;
216
+ this.log.logLevel = "error";
308
217
  }
309
218
  else if (level === 'fatal') {
310
- this.log.logLevel = "fatal" /* LogLevel.FATAL */;
219
+ this.log.logLevel = "fatal";
311
220
  }
312
221
  else {
313
222
  this.log.warn(`Invalid matterbridge logger level: ${level}. Using default level "info".`);
314
- this.log.logLevel = "info" /* LogLevel.INFO */;
223
+ this.log.logLevel = "info";
315
224
  }
316
225
  }
317
226
  else {
318
- this.log.logLevel = await this.nodeContext.get('matterbridgeLogLevel', "info" /* LogLevel.INFO */);
227
+ this.log.logLevel = await this.nodeContext.get('matterbridgeLogLevel', "info");
319
228
  }
320
229
  MatterbridgeEndpoint.logLevel = this.log.logLevel;
321
- // Create the file logger for matterbridge (context: matterbridgeFileLog)
322
230
  if (hasParameter('filelogger') || (await this.nodeContext.get('matterbridgeFileLog', false))) {
323
231
  AnsiLogger.setGlobalLogfile(path.join(this.matterbridgeDirectory, this.matterbrideLoggerFile), this.log.logLevel, true);
324
232
  this.matterbridgeInformation.fileLogger = true;
325
233
  }
326
234
  this.log.notice('Matterbridge is starting...');
327
235
  this.log.debug(`Matterbridge logLevel: ${this.log.logLevel} fileLoger: ${this.matterbridgeInformation.fileLogger}.`);
328
- // Set matter.js logger level, format and logger (context: matterLogLevel)
329
236
  if (hasParameter('matterlogger')) {
330
237
  const level = getParameter('matterlogger');
331
238
  if (level === 'debug') {
@@ -356,7 +263,6 @@ export class Matterbridge extends EventEmitter {
356
263
  }
357
264
  Logger.format = MatterLogFormat.ANSI;
358
265
  Logger.setLogger('default', this.createMatterLogger());
359
- // Create the file logger for matter.js (context: matterFileLog)
360
266
  if (hasParameter('matterfilelogger') || (await this.nodeContext.get('matterFileLog', false))) {
361
267
  this.matterbridgeInformation.matterFileLogger = true;
362
268
  Logger.addLogger('matterfilelogger', await this.createMatterFileLogger(path.join(this.matterbridgeDirectory, this.matterLoggerFile), true), {
@@ -365,7 +271,6 @@ export class Matterbridge extends EventEmitter {
365
271
  });
366
272
  }
367
273
  this.log.debug(`Matter logLevel: ${Logger.defaultLogLevel} fileLoger: ${this.matterbridgeInformation.matterFileLogger}.`);
368
- // Set the interface to use for matter server node mdnsInterface
369
274
  if (hasParameter('mdnsinterface')) {
370
275
  this.mdnsInterface = getParameter('mdnsinterface');
371
276
  }
@@ -374,7 +279,6 @@ export class Matterbridge extends EventEmitter {
374
279
  if (this.mdnsInterface === '')
375
280
  this.mdnsInterface = undefined;
376
281
  }
377
- // Validate mdnsInterface
378
282
  if (this.mdnsInterface) {
379
283
  const networkInterfaces = os.networkInterfaces();
380
284
  const availableInterfaces = Object.keys(networkInterfaces);
@@ -388,7 +292,6 @@ export class Matterbridge extends EventEmitter {
388
292
  }
389
293
  if (this.mdnsInterface)
390
294
  this.environment.vars.set('mdns.networkInterface', this.mdnsInterface);
391
- // Set the listeningAddressIpv4 for the matter commissioning server
392
295
  if (hasParameter('ipv4address')) {
393
296
  this.ipv4address = getParameter('ipv4address');
394
297
  }
@@ -397,7 +300,6 @@ export class Matterbridge extends EventEmitter {
397
300
  if (this.ipv4address === '')
398
301
  this.ipv4address = undefined;
399
302
  }
400
- // Set the listeningAddressIpv6 for the matter commissioning server
401
303
  if (hasParameter('ipv6address')) {
402
304
  this.ipv6address = getParameter('ipv6address');
403
305
  }
@@ -406,17 +308,12 @@ export class Matterbridge extends EventEmitter {
406
308
  if (this.ipv6address === '')
407
309
  this.ipv6address = undefined;
408
310
  }
409
- // Initialize PluginManager
410
311
  this.plugins = new PluginManager(this);
411
312
  await this.plugins.loadFromStorage();
412
- // Initialize DeviceManager
413
313
  this.devices = new DeviceManager(this, this.nodeContext);
414
- // Get the plugins from node storage and create the plugins node storage contexts
415
314
  for (const plugin of this.plugins) {
416
315
  const packageJson = await this.plugins.parse(plugin);
417
316
  if (packageJson === null && !hasParameter('add') && !hasParameter('remove') && !hasParameter('enable') && !hasParameter('disable') && !hasParameter('reset') && !hasParameter('factoryreset')) {
418
- // Try to reinstall the plugin from npm (for Docker pull and external plugins)
419
- // We don't do this when the add and other parameters are set because we shut down the process after adding the plugin
420
317
  this.log.info(`Error parsing plugin ${plg}${plugin.name}${nf}. Trying to reinstall it from npm.`);
421
318
  try {
422
319
  await this.spawnCommand('npm', ['install', '-g', plugin.name, '--omit=dev', '--verbose']);
@@ -438,7 +335,6 @@ export class Matterbridge extends EventEmitter {
438
335
  await plugin.nodeContext.set('description', plugin.description);
439
336
  await plugin.nodeContext.set('author', plugin.author);
440
337
  }
441
- // Log system info and create .matterbridge directory
442
338
  await this.logNodeAndSystemInfo();
443
339
  this.log.notice(`Matterbridge version ${this.matterbridgeVersion} ` +
444
340
  `${hasParameter('bridge') || (!hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'bridge') ? 'mode bridge ' : ''}` +
@@ -446,7 +342,6 @@ export class Matterbridge extends EventEmitter {
446
342
  `${hasParameter('controller') ? 'mode controller ' : ''}` +
447
343
  `${this.restartMode !== '' ? 'restart mode ' + this.restartMode + ' ' : ''}` +
448
344
  `running on ${this.systemInformation.osType} (v.${this.systemInformation.osRelease}) platform ${this.systemInformation.osPlatform} arch ${this.systemInformation.osArch}`);
449
- // Check node version and throw error
450
345
  const minNodeVersion = 18;
451
346
  const nodeVersion = process.versions.node;
452
347
  const versionMajor = parseInt(nodeVersion.split('.')[0]);
@@ -454,15 +349,9 @@ export class Matterbridge extends EventEmitter {
454
349
  this.log.error(`Node version ${versionMajor} is not supported. Please upgrade to ${minNodeVersion} or above.`);
455
350
  throw new Error(`Node version ${versionMajor} is not supported. Please upgrade to ${minNodeVersion} or above.`);
456
351
  }
457
- // Parse command line
458
352
  await this.parseCommandLine();
459
353
  this.initialized = true;
460
354
  }
461
- /**
462
- * Parses the command line arguments and performs the corresponding actions.
463
- * @private
464
- * @returns {Promise<void>} A promise that resolves when the command line arguments have been processed, or the process exits.
465
- */
466
355
  async parseCommandLine() {
467
356
  if (hasParameter('help')) {
468
357
  this.log.info(`\nUsage: matterbridge [options]\n
@@ -572,7 +461,6 @@ export class Matterbridge extends EventEmitter {
572
461
  await this.shutdownProcessAndFactoryReset();
573
462
  return;
574
463
  }
575
- // Start the matter storage and create the matterbridge context
576
464
  try {
577
465
  await this.startMatterStorage();
578
466
  }
@@ -580,12 +468,10 @@ export class Matterbridge extends EventEmitter {
580
468
  this.log.fatal(`Fatal error creating matter storage: ${error instanceof Error ? error.message : error}`);
581
469
  throw new Error(`Fatal error creating matter storage: ${error instanceof Error ? error.message : error}`);
582
470
  }
583
- // Clear the matterbridge context if the reset parameter is set
584
471
  if (hasParameter('reset') && getParameter('reset') === undefined) {
585
472
  await this.shutdownProcessAndReset();
586
473
  return;
587
474
  }
588
- // Clear matterbridge plugin context if the reset parameter is set
589
475
  if (hasParameter('reset') && getParameter('reset') !== undefined) {
590
476
  this.log.debug(`Reset plugin ${getParameter('reset')}`);
591
477
  const plugin = this.plugins.get(getParameter('reset'));
@@ -607,10 +493,8 @@ export class Matterbridge extends EventEmitter {
607
493
  this.emit('shutdown');
608
494
  return;
609
495
  }
610
- // Initialize frontend
611
496
  if (getIntParameter('frontend') !== 0 || getIntParameter('frontend') === undefined)
612
497
  await this.frontend.start(getIntParameter('frontend'));
613
- // Check each 60 minutes the latest versions
614
498
  this.checkUpdateInterval = setInterval(() => {
615
499
  this.getMatterbridgeLatestVersion();
616
500
  for (const plugin of this.plugins) {
@@ -618,24 +502,20 @@ export class Matterbridge extends EventEmitter {
618
502
  }
619
503
  this.frontend.wssSendRefreshRequired();
620
504
  }, 60 * 60 * 1000);
621
- // Start the matterbridge in mode test
622
505
  if (hasParameter('test')) {
623
506
  this.bridgeMode = 'bridge';
624
507
  MatterbridgeEndpoint.bridgeMode = 'bridge';
625
508
  return;
626
509
  }
627
- // Start the matterbridge in mode controller
628
510
  if (hasParameter('controller')) {
629
511
  this.bridgeMode = 'controller';
630
512
  await this.startController();
631
513
  return;
632
514
  }
633
- // Check if the bridge mode is set and start matterbridge in bridge mode if not set
634
515
  if (!hasParameter('bridge') && !hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === '') {
635
516
  this.log.info('Setting default matterbridge start mode to bridge');
636
517
  await this.nodeContext?.set('bridgeMode', 'bridge');
637
518
  }
638
- // Start matterbridge in bridge mode
639
519
  if (hasParameter('bridge') || (!hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'bridge')) {
640
520
  this.bridgeMode = 'bridge';
641
521
  MatterbridgeEndpoint.bridgeMode = 'bridge';
@@ -643,7 +523,6 @@ export class Matterbridge extends EventEmitter {
643
523
  await this.startBridge();
644
524
  return;
645
525
  }
646
- // Start matterbridge in childbridge mode
647
526
  if (hasParameter('childbridge') || (!hasParameter('bridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'childbridge')) {
648
527
  this.bridgeMode = 'childbridge';
649
528
  MatterbridgeEndpoint.bridgeMode = 'childbridge';
@@ -652,28 +531,16 @@ export class Matterbridge extends EventEmitter {
652
531
  return;
653
532
  }
654
533
  }
655
- /**
656
- * Asynchronously loads and starts the registered plugins.
657
- *
658
- * This method is responsible for initializing and staarting all enabled plugins.
659
- * It ensures that each plugin is properly loaded and started before the bridge starts.
660
- *
661
- * @returns {Promise<void>} A promise that resolves when all plugins have been loaded and started.
662
- */
663
534
  async startPlugins() {
664
- // Check, load and start the plugins
665
535
  for (const plugin of this.plugins) {
666
536
  plugin.configJson = await this.plugins.loadConfig(plugin);
667
537
  plugin.schemaJson = await this.plugins.loadSchema(plugin);
668
- // Check if the plugin is available
669
538
  if (!(await this.plugins.resolve(plugin.path))) {
670
539
  this.log.error(`Plugin ${plg}${plugin.name}${er} not found or not validated. Disabling it.`);
671
540
  plugin.enabled = false;
672
541
  plugin.error = true;
673
542
  continue;
674
543
  }
675
- // Check if the plugin has a new version
676
- // this.getPluginLatestVersion(plugin); // No await do it asyncronously
677
544
  if (!plugin.enabled) {
678
545
  this.log.info(`Plugin ${plg}${plugin.name}${nf} not enabled`);
679
546
  continue;
@@ -687,26 +554,20 @@ export class Matterbridge extends EventEmitter {
687
554
  plugin.addedDevices = undefined;
688
555
  plugin.qrPairingCode = undefined;
689
556
  plugin.manualPairingCode = undefined;
690
- this.plugins.load(plugin, true, 'Matterbridge is starting'); // No await do it asyncronously
557
+ this.plugins.load(plugin, true, 'Matterbridge is starting');
691
558
  }
692
559
  this.frontend.wssSendRefreshRequired();
693
560
  }
694
- /**
695
- * Registers the process handlers for uncaughtException, unhandledRejection, SIGINT and SIGTERM.
696
- * When either of these signals are received, the cleanup method is called with an appropriate message.
697
- */
698
561
  registerProcessHandlers() {
699
562
  this.log.debug(`Registering uncaughtException and unhandledRejection handlers...`);
700
563
  process.removeAllListeners('uncaughtException');
701
564
  process.removeAllListeners('unhandledRejection');
702
565
  this.exceptionHandler = async (error) => {
703
566
  this.log.fatal('Unhandled Exception detected at:', error.stack || error, rs);
704
- // await this.cleanup('Unhandled Exception detected, cleaning up...');
705
567
  };
706
568
  process.on('uncaughtException', this.exceptionHandler);
707
569
  this.rejectionHandler = async (reason, promise) => {
708
570
  this.log.fatal('Unhandled Rejection detected at:', promise, 'reason:', reason instanceof Error ? reason.stack : reason, rs);
709
- // await this.cleanup('Unhandled Rejection detected, cleaning up...');
710
571
  };
711
572
  process.on('unhandledRejection', this.rejectionHandler);
712
573
  this.log.debug(`Registering SIGINT and SIGTERM signal handlers...`);
@@ -719,9 +580,6 @@ export class Matterbridge extends EventEmitter {
719
580
  };
720
581
  process.on('SIGTERM', this.sigtermHandler);
721
582
  }
722
- /**
723
- * Deregisters the process uncaughtException, unhandledRejection, SIGINT and SIGTERM signal handlers.
724
- */
725
583
  deregisterProcesslHandlers() {
726
584
  this.log.debug(`Deregistering uncaughtException and unhandledRejection handlers...`);
727
585
  if (this.exceptionHandler)
@@ -738,17 +596,12 @@ export class Matterbridge extends EventEmitter {
738
596
  process.off('SIGTERM', this.sigtermHandler);
739
597
  this.sigtermHandler = undefined;
740
598
  }
741
- /**
742
- * Logs the node and system information.
743
- */
744
599
  async logNodeAndSystemInfo() {
745
- // IP address information
746
600
  const networkInterfaces = os.networkInterfaces();
747
601
  this.systemInformation.interfaceName = '';
748
602
  this.systemInformation.ipv4Address = '';
749
603
  this.systemInformation.ipv6Address = '';
750
604
  for (const [interfaceName, interfaceDetails] of Object.entries(networkInterfaces)) {
751
- // this.log.debug(`Checking interface: '${interfaceName}' for '${this.mdnsInterface}'`);
752
605
  if (this.mdnsInterface && interfaceName !== this.mdnsInterface)
753
606
  continue;
754
607
  if (!interfaceDetails) {
@@ -774,22 +627,19 @@ export class Matterbridge extends EventEmitter {
774
627
  break;
775
628
  }
776
629
  }
777
- // Node information
778
630
  this.systemInformation.nodeVersion = process.versions.node;
779
631
  const versionMajor = parseInt(this.systemInformation.nodeVersion.split('.')[0]);
780
632
  const versionMinor = parseInt(this.systemInformation.nodeVersion.split('.')[1]);
781
633
  const versionPatch = parseInt(this.systemInformation.nodeVersion.split('.')[2]);
782
- // Host system information
783
634
  this.systemInformation.hostname = os.hostname();
784
635
  this.systemInformation.user = os.userInfo().username;
785
- this.systemInformation.osType = os.type(); // "Windows_NT", "Darwin", etc.
786
- this.systemInformation.osRelease = os.release(); // Kernel version
787
- this.systemInformation.osPlatform = os.platform(); // "win32", "linux", "darwin", etc.
788
- this.systemInformation.osArch = os.arch(); // "x64", "arm", etc.
789
- this.systemInformation.totalMemory = (os.totalmem() / 1024 / 1024 / 1024).toFixed(2) + ' GB'; // Convert to GB
790
- this.systemInformation.freeMemory = (os.freemem() / 1024 / 1024 / 1024).toFixed(2) + ' GB'; // Convert to GB
791
- this.systemInformation.systemUptime = (os.uptime() / 60 / 60).toFixed(2) + ' hours'; // Convert to hours
792
- // Log the system information
636
+ this.systemInformation.osType = os.type();
637
+ this.systemInformation.osRelease = os.release();
638
+ this.systemInformation.osPlatform = os.platform();
639
+ this.systemInformation.osArch = os.arch();
640
+ this.systemInformation.totalMemory = (os.totalmem() / 1024 / 1024 / 1024).toFixed(2) + ' GB';
641
+ this.systemInformation.freeMemory = (os.freemem() / 1024 / 1024 / 1024).toFixed(2) + ' GB';
642
+ this.systemInformation.systemUptime = (os.uptime() / 60 / 60).toFixed(2) + ' hours';
793
643
  this.log.debug('Host System Information:');
794
644
  this.log.debug(`- Hostname: ${this.systemInformation.hostname}`);
795
645
  this.log.debug(`- User: ${this.systemInformation.user}`);
@@ -805,19 +655,15 @@ export class Matterbridge extends EventEmitter {
805
655
  this.log.debug(`- Total Memory: ${this.systemInformation.totalMemory}`);
806
656
  this.log.debug(`- Free Memory: ${this.systemInformation.freeMemory}`);
807
657
  this.log.debug(`- System Uptime: ${this.systemInformation.systemUptime}`);
808
- // Home directory
809
658
  this.homeDirectory = getParameter('homedir') ?? os.homedir();
810
659
  this.matterbridgeInformation.homeDirectory = this.homeDirectory;
811
660
  this.log.debug(`Home Directory: ${this.homeDirectory}`);
812
- // Package root directory
813
661
  const currentFileDirectory = path.dirname(fileURLToPath(import.meta.url));
814
662
  this.rootDirectory = path.resolve(currentFileDirectory, '../');
815
663
  this.matterbridgeInformation.rootDirectory = this.rootDirectory;
816
664
  this.log.debug(`Root Directory: ${this.rootDirectory}`);
817
- // Global node_modules directory
818
665
  if (this.nodeContext)
819
666
  this.globalModulesDirectory = this.matterbridgeInformation.globalModulesDirectory = await this.nodeContext.get('globalModulesDirectory', '');
820
- // First run of Matterbridge so the node storage is empty
821
667
  if (this.globalModulesDirectory === '') {
822
668
  try {
823
669
  this.globalModulesDirectory = await this.getGlobalNodeModules();
@@ -831,20 +677,6 @@ export class Matterbridge extends EventEmitter {
831
677
  }
832
678
  else
833
679
  this.log.debug(`Global node_modules Directory: ${this.globalModulesDirectory}`);
834
- /* removed cause is too expensive for the shelly board and not really needed. Why should it change the globalModulesDirectory?
835
- else {
836
- this.getGlobalNodeModules()
837
- .then(async (globalModulesDirectory) => {
838
- this.globalModulesDirectory = globalModulesDirectory;
839
- this.matterbridgeInformation.globalModulesDirectory = this.globalModulesDirectory;
840
- this.log.debug(`Global node_modules Directory: ${this.globalModulesDirectory}`);
841
- await this.nodeContext?.set<string>('globalModulesDirectory', this.globalModulesDirectory);
842
- })
843
- .catch((error) => {
844
- this.log.error(`Error getting global node_modules directory: ${error}`);
845
- });
846
- }*/
847
- // Create the data directory .matterbridge in the home directory
848
680
  this.matterbridgeDirectory = path.join(this.homeDirectory, '.matterbridge');
849
681
  this.matterbridgeInformation.matterbridgeDirectory = this.matterbridgeDirectory;
850
682
  try {
@@ -868,7 +700,6 @@ export class Matterbridge extends EventEmitter {
868
700
  }
869
701
  }
870
702
  this.log.debug(`Matterbridge Directory: ${this.matterbridgeDirectory}`);
871
- // Create the plugin directory Matterbridge in the home directory
872
703
  this.matterbridgePluginDirectory = path.join(this.homeDirectory, 'Matterbridge');
873
704
  this.matterbridgeInformation.matterbridgePluginDirectory = this.matterbridgePluginDirectory;
874
705
  try {
@@ -892,28 +723,18 @@ export class Matterbridge extends EventEmitter {
892
723
  }
893
724
  }
894
725
  this.log.debug(`Matterbridge Plugin Directory: ${this.matterbridgePluginDirectory}`);
895
- // Matterbridge version
896
726
  const packageJson = JSON.parse(await fs.readFile(path.join(this.rootDirectory, 'package.json'), 'utf-8'));
897
727
  this.matterbridgeVersion = this.matterbridgeLatestVersion = packageJson.version;
898
728
  this.matterbridgeInformation.matterbridgeVersion = this.matterbridgeInformation.matterbridgeLatestVersion = this.matterbridgeVersion;
899
729
  this.log.debug(`Matterbridge Version: ${this.matterbridgeVersion}`);
900
- // Matterbridge latest version
901
730
  if (this.nodeContext)
902
731
  this.matterbridgeLatestVersion = await this.nodeContext.get('matterbridgeLatestVersion', this.matterbridgeVersion);
903
732
  this.log.debug(`Matterbridge Latest Version: ${this.matterbridgeLatestVersion}`);
904
- // this.getMatterbridgeLatestVersion();
905
- // Current working directory
906
733
  const currentDir = process.cwd();
907
734
  this.log.debug(`Current Working Directory: ${currentDir}`);
908
- // Command line arguments (excluding 'node' and the script name)
909
735
  const cmdArgs = process.argv.slice(2).join(' ');
910
736
  this.log.debug(`Command Line Arguments: ${cmdArgs}`);
911
737
  }
912
- /**
913
- * Retrieves the latest version of a package from the npm registry.
914
- * @param packageName - The name of the package.
915
- * @returns A Promise that resolves to the latest version of the package.
916
- */
917
738
  async getLatestVersion(packageName) {
918
739
  return new Promise((resolve, reject) => {
919
740
  this.execRunningCount++;
@@ -928,16 +749,7 @@ export class Matterbridge extends EventEmitter {
928
749
  });
929
750
  });
930
751
  }
931
- /**
932
- * Retrieves the path to the global Node.js modules directory.
933
- * @returns A promise that resolves to the path of the global Node.js modules directory.
934
- */
935
752
  async getGlobalNodeModules() {
936
- /*
937
- const { Module } = await import('module'); // Dynamic import to access the `Module` class
938
- const globalPaths = 'globalPaths' in Module && Array.isArray(Module.globalPaths) && typeof Module.globalPaths[0] === 'string' ? (Module.globalPaths as string[])[0] : '';
939
- this.log.debug('Module.globalPaths:', globalPaths);
940
- */
941
753
  return new Promise((resolve, reject) => {
942
754
  this.execRunningCount++;
943
755
  exec('npm root -g', (error, stdout) => {
@@ -951,11 +763,6 @@ export class Matterbridge extends EventEmitter {
951
763
  });
952
764
  });
953
765
  }
954
- /**
955
- * Retrieves the latest version of Matterbridge and performs necessary actions based on the version comparison.
956
- * @private
957
- * @returns {Promise<void>} A promise that resolves when the latest version is retrieved and actions are performed.
958
- */
959
766
  async getMatterbridgeLatestVersion() {
960
767
  this.getLatestVersion('matterbridge')
961
768
  .then(async (matterbridgeLatestVersion) => {
@@ -972,19 +779,8 @@ export class Matterbridge extends EventEmitter {
972
779
  })
973
780
  .catch((error) => {
974
781
  this.log.error(`Error getting Matterbridge latest version: ${error.message}`);
975
- // error.stack && this.log.debug(error.stack);
976
782
  });
977
783
  }
978
- /**
979
- * Retrieves the latest version of a plugin and updates the plugin's latestVersion property.
980
- * If the plugin's version is different from the latest version, logs a warning message.
981
- * If the plugin's version is the same as the latest version, logs an info message.
982
- * If there is an error retrieving the latest version, logs an error message.
983
- *
984
- * @private
985
- * @param {RegisteredPlugin} plugin - The plugin for which to retrieve the latest version.
986
- * @returns {Promise<void>} A promise that resolves when the latest version is retrieved and actions are performed.
987
- */
988
784
  async getPluginLatestVersion(plugin) {
989
785
  this.getLatestVersion(plugin.name)
990
786
  .then(async (latestVersion) => {
@@ -996,54 +792,40 @@ export class Matterbridge extends EventEmitter {
996
792
  })
997
793
  .catch((error) => {
998
794
  this.log.error(`Error getting ${plg}${plugin.name}${er} latest version: ${error.message}`);
999
- // error.stack && this.log.debug(error.stack);
1000
795
  });
1001
796
  }
1002
- /**
1003
- * Creates a MatterLogger function to show the matter.js log messages in AnsiLogger (for the frontend).
1004
- *
1005
- * @returns {Function} The MatterLogger function.
1006
- */
1007
797
  createMatterLogger() {
1008
- const matterLogger = new AnsiLogger({ logName: 'Matter', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: "debug" /* LogLevel.DEBUG */ });
798
+ const matterLogger = new AnsiLogger({ logName: 'Matter', logTimestampFormat: 4, logLevel: "debug" });
1009
799
  return (_level, formattedLog) => {
1010
800
  const logger = formattedLog.slice(44, 44 + 20).trim();
1011
801
  const message = formattedLog.slice(65);
1012
802
  matterLogger.logName = logger;
1013
803
  switch (_level) {
1014
804
  case MatterLogLevel.DEBUG:
1015
- matterLogger.log("debug" /* LogLevel.DEBUG */, message);
805
+ matterLogger.log("debug", message);
1016
806
  break;
1017
807
  case MatterLogLevel.INFO:
1018
- matterLogger.log("info" /* LogLevel.INFO */, message);
808
+ matterLogger.log("info", message);
1019
809
  break;
1020
810
  case MatterLogLevel.NOTICE:
1021
- matterLogger.log("notice" /* LogLevel.NOTICE */, message);
811
+ matterLogger.log("notice", message);
1022
812
  break;
1023
813
  case MatterLogLevel.WARN:
1024
- matterLogger.log("warn" /* LogLevel.WARN */, message);
814
+ matterLogger.log("warn", message);
1025
815
  break;
1026
816
  case MatterLogLevel.ERROR:
1027
- matterLogger.log("error" /* LogLevel.ERROR */, message);
817
+ matterLogger.log("error", message);
1028
818
  break;
1029
819
  case MatterLogLevel.FATAL:
1030
- matterLogger.log("fatal" /* LogLevel.FATAL */, message);
820
+ matterLogger.log("fatal", message);
1031
821
  break;
1032
822
  default:
1033
- matterLogger.log("debug" /* LogLevel.DEBUG */, message);
823
+ matterLogger.log("debug", message);
1034
824
  break;
1035
825
  }
1036
826
  };
1037
827
  }
1038
- /**
1039
- * Creates a Matter File Logger.
1040
- *
1041
- * @param {string} filePath - The path to the log file.
1042
- * @param {boolean} [unlink=false] - Whether to unlink the log file before creating a new one.
1043
- * @returns {Function} - A function that logs formatted messages to the log file.
1044
- */
1045
828
  async createMatterFileLogger(filePath, unlink = false) {
1046
- // 2024-08-21 08:55:19.488 DEBUG InteractionMessenger Sending DataReport chunk with 28 attributes and 0 events: 1004 bytes
1047
829
  let fileSize = 0;
1048
830
  if (unlink) {
1049
831
  try {
@@ -1092,21 +874,12 @@ export class Matterbridge extends EventEmitter {
1092
874
  }
1093
875
  };
1094
876
  }
1095
- /**
1096
- * Restarts the process by exiting the current instance and loading a new instance.
1097
- */
1098
877
  async restartProcess() {
1099
878
  await this.cleanup('restarting...', true);
1100
879
  }
1101
- /**
1102
- * Shut down the process by exiting the current process.
1103
- */
1104
880
  async shutdownProcess() {
1105
881
  await this.cleanup('shutting down...', false);
1106
882
  }
1107
- /**
1108
- * Update matterbridge and and shut down the process.
1109
- */
1110
883
  async updateProcess() {
1111
884
  this.log.info('Updating matterbridge...');
1112
885
  try {
@@ -1119,9 +892,6 @@ export class Matterbridge extends EventEmitter {
1119
892
  this.frontend.wssSendRestartRequired();
1120
893
  await this.cleanup('updating...', false);
1121
894
  }
1122
- /**
1123
- * Unregister all devices and shut down the process.
1124
- */
1125
895
  async unregisterAndShutdownProcess() {
1126
896
  this.log.info('Unregistering all devices and shutting down...');
1127
897
  for (const plugin of this.plugins) {
@@ -1129,9 +899,6 @@ export class Matterbridge extends EventEmitter {
1129
899
  }
1130
900
  await this.cleanup('unregistered all devices and shutting down...', false);
1131
901
  }
1132
- /**
1133
- * Reset commissioning and shut down the process.
1134
- */
1135
902
  async shutdownProcessAndReset() {
1136
903
  this.log.info('Resetting Matterbridge commissioning information...');
1137
904
  await this.matterStorageManager?.createContext('events')?.clearAll();
@@ -1143,12 +910,8 @@ export class Matterbridge extends EventEmitter {
1143
910
  this.log.info('Matter storage reset done! Remove the bridge from the controller.');
1144
911
  await this.cleanup('shutting down with reset...', false);
1145
912
  }
1146
- /**
1147
- * Factory reset and shut down the process.
1148
- */
1149
913
  async shutdownProcessAndFactoryReset() {
1150
914
  try {
1151
- // Delete old matter storage file and backup
1152
915
  const file = path.join(this.matterbridgeDirectory, 'matterbridge' + (getParameter('profile') ? '.' + getParameter('profile') : '') + '.json');
1153
916
  this.log.info(`Unlinking old matter storage file: ${file}`);
1154
917
  await fs.unlink(file);
@@ -1162,7 +925,6 @@ export class Matterbridge extends EventEmitter {
1162
925
  }
1163
926
  }
1164
927
  try {
1165
- // Delete matter node storage directory with its subdirectories and backup
1166
928
  const dir = path.join(this.matterbridgeDirectory, 'matterstorage' + (getParameter('profile') ? '.' + getParameter('profile') : ''));
1167
929
  this.log.info(`Removing matter node storage directory: ${dir}`);
1168
930
  await fs.rm(dir, { recursive: true });
@@ -1176,7 +938,6 @@ export class Matterbridge extends EventEmitter {
1176
938
  }
1177
939
  }
1178
940
  try {
1179
- // Delete node storage directory with its subdirectories and backup
1180
941
  const dir = path.join(this.matterbridgeDirectory, 'storage' + (getParameter('profile') ? '.' + getParameter('profile') : ''));
1181
942
  this.log.info(`Removing storage directory: ${dir}`);
1182
943
  await fs.rm(dir, { recursive: true });
@@ -1196,41 +957,30 @@ export class Matterbridge extends EventEmitter {
1196
957
  this.devices.clear();
1197
958
  await this.cleanup('shutting down with factory reset...', false);
1198
959
  }
1199
- /**
1200
- * Cleans up the Matterbridge instance.
1201
- * @param message - The cleanup message.
1202
- * @param restart - Indicates whether to restart the instance after cleanup. Default is `false`.
1203
- * @returns A promise that resolves when the cleanup is completed.
1204
- */
1205
960
  async cleanup(message, restart = false) {
1206
961
  if (this.initialized && !this.hasCleanupStarted) {
1207
962
  this.hasCleanupStarted = true;
1208
963
  this.log.info(message);
1209
- // Clear the start matter interval
1210
964
  if (this.startMatterInterval) {
1211
965
  clearInterval(this.startMatterInterval);
1212
966
  this.startMatterInterval = undefined;
1213
967
  this.log.debug('Start matter interval cleared');
1214
968
  }
1215
- // Clear the check update interval
1216
969
  if (this.checkUpdateInterval) {
1217
970
  clearInterval(this.checkUpdateInterval);
1218
971
  this.checkUpdateInterval = undefined;
1219
972
  this.log.debug('Check update interval cleared');
1220
973
  }
1221
- // Clear the configure timeout
1222
974
  if (this.configureTimeout) {
1223
975
  clearTimeout(this.configureTimeout);
1224
976
  this.configureTimeout = undefined;
1225
977
  this.log.debug('Matterbridge configure timeout cleared');
1226
978
  }
1227
- // Clear the reachability timeout
1228
979
  if (this.reachabilityTimeout) {
1229
980
  clearTimeout(this.reachabilityTimeout);
1230
981
  this.reachabilityTimeout = undefined;
1231
982
  this.log.debug('Matterbridge reachability timeout cleared');
1232
983
  }
1233
- // Calling the shutdown method of each plugin and clear the plugins reachability timeout
1234
984
  for (const plugin of this.plugins) {
1235
985
  if (!plugin.enabled || plugin.error)
1236
986
  continue;
@@ -1241,13 +991,12 @@ export class Matterbridge extends EventEmitter {
1241
991
  this.log.debug(`Plugin ${plg}${plugin.name}${db} reachability timeout cleared`);
1242
992
  }
1243
993
  }
1244
- // Stop the frontend
1245
994
  this.frontend.stop();
1246
- // Stopping matter server nodes
1247
995
  this.log.info(`Stopping matter server nodes in ${this.bridgeMode} mode...`);
1248
996
  if (this.bridgeMode === 'bridge') {
1249
997
  if (this.serverNode) {
1250
998
  await this.stopServerNode(this.serverNode);
999
+ this.serverNode = undefined;
1251
1000
  this.log.info(`Stopped matter server node for Matterbridge`);
1252
1001
  }
1253
1002
  }
@@ -1255,41 +1004,22 @@ export class Matterbridge extends EventEmitter {
1255
1004
  for (const plugin of this.plugins.array()) {
1256
1005
  if (plugin.serverNode) {
1257
1006
  await this.stopServerNode(plugin.serverNode);
1007
+ plugin.serverNode = undefined;
1258
1008
  this.log.info(`Stopped matter server node for ${plugin.name}`);
1259
1009
  }
1260
1010
  }
1261
1011
  }
1262
1012
  this.log.info('Stopped matter server nodes');
1263
- // Stop matter MdnsService
1264
- // await this.environment.get(MdnsService)[Symbol.asyncDispose]();
1265
- // this.log.info('Stopped MdnsService');
1266
- // Stop matter storage
1267
1013
  await this.stopMatterStorage();
1268
- // Remove the matterfilelogger
1269
1014
  try {
1270
1015
  Logger.removeLogger('matterfilelogger');
1271
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1272
1016
  }
1273
1017
  catch (error) {
1274
- // this.log.debug(`Error removing the matterfilelogger for file ${CYAN}${path.join(this.matterbridgeDirectory, this.matterLoggerFile)}${er}: ${error instanceof Error ? error.message : error}`);
1275
1018
  }
1276
- // Serialize registeredDevices
1277
1019
  if (this.nodeStorage && this.nodeContext) {
1278
- this.log.info('Saving registered devices...');
1279
- const serializedRegisteredDevices = [];
1280
- this.devices.forEach(async (device) => {
1281
- const serializedMatterbridgeDevice = device.serialize();
1282
- // this.log.info(`- ${serializedMatterbridgeDevice.deviceName}${rs}\n`, serializedMatterbridgeDevice);
1283
- if (serializedMatterbridgeDevice)
1284
- serializedRegisteredDevices.push(serializedMatterbridgeDevice);
1285
- });
1286
- await this.nodeContext.set('devices', serializedRegisteredDevices);
1287
- this.log.info(`Saved registered devices (${serializedRegisteredDevices?.length})`);
1288
- // Clear nodeContext and nodeStorage (they just need 1000ms to write the data to disk)
1289
1020
  this.log.debug(`Closing node storage context for ${plg}Matterbridge${db}...`);
1290
1021
  await this.nodeContext.close();
1291
1022
  this.nodeContext = undefined;
1292
- // Clear nodeContext for each plugin (they just need 1000ms to write the data to disk)
1293
1023
  for (const plugin of this.plugins) {
1294
1024
  if (plugin.nodeContext) {
1295
1025
  this.log.debug(`Closing node storage context for plugin ${plg}${plugin.name}${db}...`);
@@ -1306,13 +1036,12 @@ export class Matterbridge extends EventEmitter {
1306
1036
  }
1307
1037
  this.plugins.clear();
1308
1038
  this.devices.clear();
1309
- // Deregisters the process handlers
1310
1039
  this.deregisterProcesslHandlers();
1311
1040
  if (restart) {
1312
1041
  if (message === 'updating...') {
1313
1042
  this.log.info('Cleanup completed. Updating...');
1314
1043
  Matterbridge.instance = undefined;
1315
- this.emit('update'); // Restart the process but the update has been done before
1044
+ this.emit('update');
1316
1045
  }
1317
1046
  else if (message === 'restarting...') {
1318
1047
  this.log.info('Cleanup completed. Restarting...');
@@ -1329,14 +1058,6 @@ export class Matterbridge extends EventEmitter {
1329
1058
  this.initialized = false;
1330
1059
  }
1331
1060
  }
1332
- /**
1333
- * Creates and configures the server node for an accessory plugin for a given device.
1334
- *
1335
- * @param {RegisteredPlugin} plugin - The plugin to configure.
1336
- * @param {MatterbridgeEndpoint} device - The device to associate with the plugin.
1337
- * @param {boolean} [start=false] - Whether to start the server node after adding the device.
1338
- * @returns {Promise<void>} A promise that resolves when the server node for the accessory plugin is created and configured.
1339
- */
1340
1061
  async createAccessoryPlugin(plugin, device, start = false) {
1341
1062
  if (!plugin.locked && device.deviceName && device.vendorId && device.productId && device.vendorName && device.productName) {
1342
1063
  plugin.locked = true;
@@ -1348,13 +1069,6 @@ export class Matterbridge extends EventEmitter {
1348
1069
  await this.startServerNode(plugin.serverNode);
1349
1070
  }
1350
1071
  }
1351
- /**
1352
- * Creates and configures the server node for a dynamic plugin.
1353
- *
1354
- * @param {RegisteredPlugin} plugin - The plugin to configure.
1355
- * @param {boolean} [start=false] - Whether to start the server node after adding the aggregator node.
1356
- * @returns {Promise<void>} A promise that resolves when the server node for the dynamic plugin is created and configured.
1357
- */
1358
1072
  async createDynamicPlugin(plugin, start = false) {
1359
1073
  if (!plugin.locked) {
1360
1074
  plugin.locked = true;
@@ -1366,13 +1080,7 @@ export class Matterbridge extends EventEmitter {
1366
1080
  await this.startServerNode(plugin.serverNode);
1367
1081
  }
1368
1082
  }
1369
- /**
1370
- * Starts the Matterbridge in bridge mode.
1371
- * @private
1372
- * @returns {Promise<void>} A promise that resolves when the Matterbridge is started.
1373
- */
1374
1083
  async startBridge() {
1375
- // Plugins are configured by a timer when matter server is started and plugin.configured is set to true
1376
1084
  if (!this.matterStorageManager)
1377
1085
  throw new Error('No storage manager initialized');
1378
1086
  if (!this.matterbridgeContext)
@@ -1409,15 +1117,13 @@ export class Matterbridge extends EventEmitter {
1409
1117
  clearInterval(this.startMatterInterval);
1410
1118
  this.startMatterInterval = undefined;
1411
1119
  this.log.debug('Cleared startMatterInterval interval for Matterbridge');
1412
- // Start the Matter server node
1413
1120
  this.startServerNode(this.serverNode);
1414
- // Configure the plugins
1415
1121
  this.configureTimeout = setTimeout(async () => {
1416
1122
  for (const plugin of this.plugins) {
1417
1123
  if (!plugin.enabled || !plugin.loaded || !plugin.started || plugin.error)
1418
1124
  continue;
1419
1125
  try {
1420
- await this.plugins.configure(plugin); // TODO No await do it in parallel
1126
+ await this.plugins.configure(plugin);
1421
1127
  }
1422
1128
  catch (error) {
1423
1129
  plugin.error = true;
@@ -1426,7 +1132,6 @@ export class Matterbridge extends EventEmitter {
1426
1132
  }
1427
1133
  this.frontend.wssSendRefreshRequired();
1428
1134
  }, 30 * 1000);
1429
- // Setting reachability to true
1430
1135
  this.reachabilityTimeout = setTimeout(() => {
1431
1136
  this.log.info(`Setting reachability to true for ${plg}Matterbridge${db}`);
1432
1137
  if (this.serverNode)
@@ -1437,14 +1142,7 @@ export class Matterbridge extends EventEmitter {
1437
1142
  }, 60 * 1000);
1438
1143
  }, 1000);
1439
1144
  }
1440
- /**
1441
- * Starts the Matterbridge in childbridge mode.
1442
- * @private
1443
- * @returns {Promise<void>} A promise that resolves when the Matterbridge is started.
1444
- */
1445
1145
  async startChildbridge() {
1446
- // Matterbridge.addBridgedDevice creates the commissionig servers and add the devices to the the commissioning server or to the aggregator
1447
- // Plugins are configured by a timer when matter server is started and plugin.configured is set to true
1448
1146
  if (!this.matterStorageManager)
1449
1147
  throw new Error('No storage manager initialized');
1450
1148
  for (const plugin of this.plugins) {
@@ -1491,13 +1189,12 @@ export class Matterbridge extends EventEmitter {
1491
1189
  clearInterval(this.startMatterInterval);
1492
1190
  this.startMatterInterval = undefined;
1493
1191
  this.log.debug('Cleared startMatterInterval interval in childbridge mode');
1494
- // Configure the plugins
1495
1192
  this.configureTimeout = setTimeout(async () => {
1496
1193
  for (const plugin of this.plugins) {
1497
1194
  if (!plugin.enabled || !plugin.loaded || !plugin.started || plugin.error)
1498
1195
  continue;
1499
1196
  try {
1500
- await this.plugins.configure(plugin); // TODO No await do it in parallel
1197
+ await this.plugins.configure(plugin);
1501
1198
  }
1502
1199
  catch (error) {
1503
1200
  plugin.error = true;
@@ -1525,9 +1222,7 @@ export class Matterbridge extends EventEmitter {
1525
1222
  this.log.error(`Node storage context not found for plugin ${plg}${plugin.name}${er}`);
1526
1223
  continue;
1527
1224
  }
1528
- // Start the Matter server node
1529
1225
  this.startServerNode(plugin.serverNode);
1530
- // Setting reachability to true
1531
1226
  plugin.reachabilityTimeout = setTimeout(() => {
1532
1227
  this.log.info(`Setting reachability to true for ${plg}${plugin.name}${db}`);
1533
1228
  if (plugin.serverNode)
@@ -1541,219 +1236,9 @@ export class Matterbridge extends EventEmitter {
1541
1236
  }
1542
1237
  }, 1000);
1543
1238
  }
1544
- /**
1545
- * Starts the Matterbridge controller.
1546
- * @private
1547
- * @returns {Promise<void>} A promise that resolves when the Matterbridge is started.
1548
- */
1549
1239
  async startController() {
1550
- /*
1551
- if (!this.storageManager) {
1552
- this.log.error('No storage manager initialized');
1553
- await this.cleanup('No storage manager initialized');
1554
- return;
1555
- }
1556
- this.log.info('Creating context: mattercontrollerContext');
1557
- this.mattercontrollerContext = this.storageManager.createContext('mattercontrollerContext');
1558
- if (!this.mattercontrollerContext) {
1559
- this.log.error('No storage context mattercontrollerContext initialized');
1560
- await this.cleanup('No storage context mattercontrollerContext initialized');
1561
- return;
1562
- }
1563
-
1564
- this.log.debug('Starting matterbridge in mode', this.bridgeMode);
1565
- this.matterServer = await this.createMatterServer(this.storageManager);
1566
- this.log.info('Creating matter commissioning controller');
1567
- this.commissioningController = new CommissioningController({
1568
- autoConnect: false,
1569
- });
1570
- this.log.info('Adding matter commissioning controller to matter server');
1571
- await this.matterServer.addCommissioningController(this.commissioningController);
1572
-
1573
- this.log.info('Starting matter server');
1574
- await this.matterServer.start();
1575
- this.log.info('Matter server started');
1576
-
1577
- if (hasParameter('pairingcode')) {
1578
- this.log.info('Pairing device with pairingcode:', getParameter('pairingcode'));
1579
- const pairingCode = getParameter('pairingcode');
1580
- const ip = this.mattercontrollerContext.has('ip') ? this.mattercontrollerContext.get<string>('ip') : undefined;
1581
- const port = this.mattercontrollerContext.has('port') ? this.mattercontrollerContext.get<number>('port') : undefined;
1582
-
1583
- let longDiscriminator, setupPin, shortDiscriminator;
1584
- if (pairingCode !== undefined) {
1585
- const pairingCodeCodec = ManualPairingCodeCodec.decode(pairingCode);
1586
- shortDiscriminator = pairingCodeCodec.shortDiscriminator;
1587
- longDiscriminator = undefined;
1588
- setupPin = pairingCodeCodec.passcode;
1589
- this.log.info(`Data extracted from pairing code: ${Logger.toJSON(pairingCodeCodec)}`);
1590
- } else {
1591
- longDiscriminator = await this.mattercontrollerContext.get('longDiscriminator', 3840);
1592
- if (longDiscriminator > 4095) throw new Error('Discriminator value must be less than 4096');
1593
- setupPin = this.mattercontrollerContext.get('pin', 20202021);
1594
- }
1595
- if ((shortDiscriminator === undefined && longDiscriminator === undefined) || setupPin === undefined) {
1596
- throw new Error('Please specify the longDiscriminator of the device to commission with -longDiscriminator or provide a valid passcode with -passcode');
1597
- }
1598
-
1599
- const commissioningOptions: ControllerCommissioningFlowOptions = {
1600
- regulatoryLocation: GeneralCommissioning.RegulatoryLocationType.IndoorOutdoor,
1601
- regulatoryCountryCode: 'XX',
1602
- };
1603
- const options = {
1604
- commissioning: commissioningOptions,
1605
- discovery: {
1606
- knownAddress: ip !== undefined && port !== undefined ? { ip, port, type: 'udp' } : undefined,
1607
- identifierData: longDiscriminator !== undefined ? { longDiscriminator } : shortDiscriminator !== undefined ? { shortDiscriminator } : {},
1608
- },
1609
- passcode: setupPin,
1610
- } as NodeCommissioningOptions;
1611
- this.log.info('Commissioning with options:', options);
1612
- const nodeId = await this.commissioningController.commissionNode(options);
1613
- this.log.info(`Commissioning successfully done with nodeId: ${nodeId}`);
1614
- this.log.info('ActiveSessionInformation:', this.commissioningController.getActiveSessionInformation());
1615
- } // (hasParameter('pairingcode'))
1616
-
1617
- if (hasParameter('unpairall')) {
1618
- this.log.info('***Commissioning controller unpairing all nodes...');
1619
- const nodeIds = this.commissioningController.getCommissionedNodes();
1620
- for (const nodeId of nodeIds) {
1621
- this.log.info('***Commissioning controller unpairing node:', nodeId);
1622
- await this.commissioningController.removeNode(nodeId);
1623
- }
1624
- return;
1625
- }
1626
-
1627
- if (hasParameter('discover')) {
1628
- // const discover = await this.commissioningController.discoverCommissionableDevices({ productId: 0x8000, deviceType: 0xfff1 });
1629
- // console.log(discover);
1630
- }
1631
-
1632
- if (!this.commissioningController.isCommissioned()) {
1633
- this.log.info('***Commissioning controller is not commissioned: use matterbridge -controller -pairingcode [pairingcode] to commission a device');
1634
- return;
1635
- }
1636
-
1637
- const nodeIds = this.commissioningController.getCommissionedNodes();
1638
- this.log.info(`***Commissioning controller is commissioned ${this.commissioningController.isCommissioned()} and has ${nodeIds.length} nodes commisioned: `);
1639
- for (const nodeId of nodeIds) {
1640
- this.log.info(`***Connecting to commissioned node: ${nodeId}`);
1641
-
1642
- const node = await this.commissioningController.connectNode(nodeId, {
1643
- autoSubscribe: false,
1644
- attributeChangedCallback: (peerNodeId, { path: { nodeId, clusterId, endpointId, attributeName }, value }) =>
1645
- this.log.info(`***Commissioning controller attributeChangedCallback ${peerNodeId}: attribute ${nodeId}/${endpointId}/${clusterId}/${attributeName} changed to ${Logger.toJSON(value)}`),
1646
- eventTriggeredCallback: (peerNodeId, { path: { nodeId, clusterId, endpointId, eventName }, events }) =>
1647
- this.log.info(`***Commissioning controller eventTriggeredCallback ${peerNodeId}: Event ${nodeId}/${endpointId}/${clusterId}/${eventName} triggered with ${Logger.toJSON(events)}`),
1648
- stateInformationCallback: (peerNodeId, info) => {
1649
- switch (info) {
1650
- case NodeStateInformation.Connected:
1651
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} connected`);
1652
- break;
1653
- case NodeStateInformation.Disconnected:
1654
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} disconnected`);
1655
- break;
1656
- case NodeStateInformation.Reconnecting:
1657
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} reconnecting`);
1658
- break;
1659
- case NodeStateInformation.WaitingForDeviceDiscovery:
1660
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} waiting for device discovery`);
1661
- break;
1662
- case NodeStateInformation.StructureChanged:
1663
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} structure changed`);
1664
- break;
1665
- case NodeStateInformation.Decommissioned:
1666
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} decommissioned`);
1667
- break;
1668
- default:
1669
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} NodeStateInformation.${info}`);
1670
- break;
1671
- }
1672
- },
1673
- });
1674
-
1675
- node.logStructure();
1676
-
1677
- // Get the interaction client
1678
- this.log.info('Getting the interaction client');
1679
- const interactionClient = await node.getInteractionClient();
1680
- let cluster;
1681
- let attributes;
1682
-
1683
- // Log BasicInformationCluster
1684
- cluster = BasicInformationCluster;
1685
- attributes = await interactionClient.getMultipleAttributes({
1686
- attributes: [{ clusterId: cluster.id }],
1687
- });
1688
- if (attributes.length > 0) this.log.info(`Cluster: ${idn}${cluster.name}${rs}${nf} attributes:`);
1689
- attributes.forEach((attribute) => {
1690
- this.log.info(
1691
- `- 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}`,
1692
- );
1693
- });
1694
-
1695
- // Log PowerSourceCluster
1696
- cluster = PowerSourceCluster;
1697
- attributes = await interactionClient.getMultipleAttributes({
1698
- attributes: [{ clusterId: cluster.id }],
1699
- });
1700
- if (attributes.length > 0) this.log.info(`Cluster: ${idn}${cluster.name}${rs}${nf} attributes:`);
1701
- attributes.forEach((attribute) => {
1702
- this.log.info(
1703
- `- 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}`,
1704
- );
1705
- });
1706
-
1707
- // Log ThreadNetworkDiagnostics
1708
- cluster = ThreadNetworkDiagnosticsCluster;
1709
- attributes = await interactionClient.getMultipleAttributes({
1710
- attributes: [{ clusterId: cluster.id }],
1711
- });
1712
- if (attributes.length > 0) this.log.info(`Cluster: ${idn}${cluster.name}${rs}${nf} attributes:`);
1713
- attributes.forEach((attribute) => {
1714
- this.log.info(
1715
- `- 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}`,
1716
- );
1717
- });
1718
-
1719
- // Log SwitchCluster
1720
- cluster = SwitchCluster;
1721
- attributes = await interactionClient.getMultipleAttributes({
1722
- attributes: [{ clusterId: cluster.id }],
1723
- });
1724
- if (attributes.length > 0) this.log.info(`Cluster: ${idn}${cluster.name}${rs}${nf} attributes:`);
1725
- attributes.forEach((attribute) => {
1726
- this.log.info(
1727
- `- 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}`,
1728
- );
1729
- });
1730
-
1731
- this.log.info('Subscribing to all attributes and events');
1732
- await node.subscribeAllAttributesAndEvents({
1733
- ignoreInitialTriggers: false,
1734
- attributeChangedCallback: ({ path: { nodeId, clusterId, endpointId, attributeName }, version, value }) =>
1735
- this.log.info(
1736
- `***${db}Commissioning controller attributeChangedCallback version ${version}: attribute ${BLUE}${nodeId}${db}/${or}${endpointId}${db}/${hk}${getClusterNameById(clusterId)}${db}/${zb}${attributeName}${db} changed to ${typeof value === 'object' ? debugStringify(value ?? { none: true }) : value}`,
1737
- ),
1738
- eventTriggeredCallback: ({ path: { nodeId, clusterId, endpointId, eventName }, events }) => {
1739
- this.log.info(
1740
- `***${db}Commissioning controller eventTriggeredCallback: event ${BLUE}${nodeId}${db}/${or}${endpointId}${db}/${hk}${getClusterNameById(clusterId)}${db}/${zb}${eventName}${db} triggered with ${debugStringify(events ?? { none: true })}`,
1741
- );
1742
- },
1743
- });
1744
- this.log.info('Subscribed to all attributes and events');
1745
- }
1746
- */
1747
1240
  }
1748
- /** ***********************************************************************************************************************************/
1749
- /** Matter.js methods */
1750
- /** ***********************************************************************************************************************************/
1751
- /**
1752
- * Starts the matter storage process based on the specified storage type and name.
1753
- * @returns {Promise<void>} - A promise that resolves when the storage process is started.
1754
- */
1755
1241
  async startMatterStorage() {
1756
- // Setup Matter storage
1757
1242
  this.log.info(`Starting matter node storage...`);
1758
1243
  this.matterStorageService = this.environment.get(StorageService);
1759
1244
  this.log.info(`Matter node storage service created: ${this.matterStorageService.location}`);
@@ -1761,24 +1246,13 @@ export class Matterbridge extends EventEmitter {
1761
1246
  this.log.info('Matter node storage manager "Matterbridge" created');
1762
1247
  this.matterbridgeContext = await this.createServerNodeContext('Matterbridge', 'Matterbridge', bridge.code, this.aggregatorVendorId, 'Matterbridge', this.aggregatorProductId, 'Matterbridge aggregator');
1763
1248
  this.log.info('Matter node storage started');
1764
- // Backup matter storage since it is created/opened correctly
1765
1249
  await this.backupMatterStorage(path.join(this.matterbridgeDirectory, this.matterStorageName), path.join(this.matterbridgeDirectory, this.matterStorageName + '.backup'));
1766
1250
  }
1767
- /**
1768
- * Makes a backup copy of the specified matter storage directory.
1769
- *
1770
- * @param storageName - The name of the storage file to be backed up.
1771
- * @param backupName - The name of the backup file to be created.
1772
- */
1773
1251
  async backupMatterStorage(storageName, backupName) {
1774
1252
  this.log.info('Creating matter node storage backup...');
1775
1253
  await copyDirectory(storageName, backupName);
1776
1254
  this.log.info('Created matter node storage backup');
1777
1255
  }
1778
- /**
1779
- * Stops the matter storage.
1780
- * @returns {Promise<void>} A promise that resolves when the storage is stopped.
1781
- */
1782
1256
  async stopMatterStorage() {
1783
1257
  this.log.info('Closing matter node storage...');
1784
1258
  this.matterStorageManager?.close();
@@ -1787,24 +1261,6 @@ export class Matterbridge extends EventEmitter {
1787
1261
  this.matterbridgeContext = undefined;
1788
1262
  this.log.info('Matter node storage closed');
1789
1263
  }
1790
- /**
1791
- * Creates a server node storage context.
1792
- *
1793
- * @param pluginName - The name of the plugin.
1794
- * @param deviceName - The name of the device.
1795
- * @param deviceType - The deviceType of the device.
1796
- * @param vendorId - The vendor ID.
1797
- * @param vendorName - The vendor name.
1798
- * @param productId - The product ID.
1799
- * @param productName - The product name.
1800
- * @param serialNumber - The serial number of the device (optional).
1801
- * @param uniqueId - The unique ID of the device (optional).
1802
- * @param softwareVersion - The software version of the device (optional).
1803
- * @param softwareVersionString - The software version string of the device (optional).
1804
- * @param hardwareVersion - The hardware version of the device (optional).
1805
- * @param hardwareVersionString - The hardware version string of the device (optional).
1806
- * @returns The storage context for the commissioning server.
1807
- */
1808
1264
  async createServerNodeContext(pluginName, deviceName, deviceType, vendorId, vendorName, productId, productName, serialNumber) {
1809
1265
  if (!this.matterStorageService)
1810
1266
  throw new Error('No storage service initialized');
@@ -1846,33 +1302,21 @@ export class Matterbridge extends EventEmitter {
1846
1302
  this.log.debug(`- uniqueId: ${await storageContext.get('uniqueId')}`);
1847
1303
  this.log.debug(`- softwareVersion: ${await storageContext.get('softwareVersion')} softwareVersionString: ${await storageContext.get('softwareVersionString')}`);
1848
1304
  this.log.debug(`- hardwareVersion: ${await storageContext.get('hardwareVersion')} hardwareVersionString: ${await storageContext.get('hardwareVersionString')}`);
1849
- /**
1850
- * Create a Matter ServerNode, which contains the Root Endpoint and all relevant data and configuration
1851
- */
1852
1305
  const serverNode = await ServerNode.create({
1853
- // Required: Give the Node a unique ID which is used to store the state of this node
1854
1306
  id: storeId,
1855
- // Provide Network relevant configuration like the port
1856
- // Optional when operating only one device on a host, Default port is 5540
1857
1307
  network: {
1858
1308
  listeningAddressIpv4: this.ipv4address,
1859
1309
  listeningAddressIpv6: this.ipv6address,
1860
1310
  port,
1861
1311
  },
1862
- // Provide Commissioning relevant settings
1863
- // Optional for development/testing purposes
1864
1312
  commissioning: {
1865
1313
  passcode,
1866
1314
  discriminator,
1867
1315
  },
1868
- // Provide Node announcement settings
1869
- // Optional: If Ommitted some development defaults are used
1870
1316
  productDescription: {
1871
1317
  name: await storageContext.get('deviceName'),
1872
1318
  deviceType: DeviceTypeId(await storageContext.get('deviceType')),
1873
1319
  },
1874
- // Provide defaults for the BasicInformation cluster on the Root endpoint
1875
- // Optional: If Omitted some development defaults are used
1876
1320
  basicInformation: {
1877
1321
  vendorId: VendorId(await storageContext.get('vendorId')),
1878
1322
  vendorName: await storageContext.get('vendorName'),
@@ -1889,13 +1333,12 @@ export class Matterbridge extends EventEmitter {
1889
1333
  },
1890
1334
  });
1891
1335
  const sanitizeFabrics = (fabrics, resetSessions = false) => {
1892
- // New type of fabric information: Record<FabricIndex, ExposedFabricInformation>
1893
1336
  const sanitizedFabrics = this.sanitizeFabricInformations(Array.from(Object.values(fabrics)));
1894
1337
  this.log.info(`Fabrics: ${debugStringify(sanitizedFabrics)}`);
1895
1338
  if (this.bridgeMode === 'bridge') {
1896
1339
  this.matterbridgeFabricInformations = sanitizedFabrics;
1897
1340
  if (resetSessions)
1898
- this.matterbridgeSessionInformations = []; // Changed cause Invoke Matterbridge.operationalCredentials.updateFabricLabel is sent after the session is created
1341
+ this.matterbridgeSessionInformations = undefined;
1899
1342
  this.matterbridgePaired = true;
1900
1343
  }
1901
1344
  if (this.bridgeMode === 'childbridge') {
@@ -1903,20 +1346,14 @@ export class Matterbridge extends EventEmitter {
1903
1346
  if (plugin) {
1904
1347
  plugin.fabricInformations = sanitizedFabrics;
1905
1348
  if (resetSessions)
1906
- plugin.sessionInformations = []; // Changed cause Invoke Matterbridge.operationalCredentials.updateFabricLabel is sent after the session is created
1349
+ plugin.sessionInformations = undefined;
1907
1350
  plugin.paired = true;
1908
1351
  }
1909
1352
  }
1910
1353
  };
1911
- /**
1912
- * This event is triggered when the device is initially commissioned successfully.
1913
- * This means: It is added to the first fabric.
1914
- */
1915
1354
  serverNode.lifecycle.commissioned.on(() => this.log.notice(`Server node for ${storeId} was initially commissioned successfully!`));
1916
- /** This event is triggered when all fabrics are removed from the device, usually it also does a factory reset then. */
1917
1355
  serverNode.lifecycle.decommissioned.on(() => this.log.notice(`Server node for ${storeId} was fully decommissioned successfully!`));
1918
- /** This event is triggered when the device went online. This means that it is discoverable in the network. */
1919
- serverNode.lifecycle.online.on(() => {
1356
+ serverNode.lifecycle.online.on(async () => {
1920
1357
  this.log.notice(`Server node for ${storeId} is online`);
1921
1358
  if (!serverNode.lifecycle.isCommissioned) {
1922
1359
  this.log.notice(`Server node for ${storeId} is not commissioned. Pair to commission ...`);
@@ -1924,22 +1361,34 @@ export class Matterbridge extends EventEmitter {
1924
1361
  if (this.bridgeMode === 'bridge') {
1925
1362
  this.matterbridgeQrPairingCode = qrPairingCode;
1926
1363
  this.matterbridgeManualPairingCode = manualPairingCode;
1927
- this.matterbridgeFabricInformations = [];
1928
- this.matterbridgeSessionInformations = [];
1364
+ this.matterbridgeFabricInformations = undefined;
1365
+ this.matterbridgeSessionInformations = undefined;
1929
1366
  this.matterbridgePaired = false;
1930
1367
  this.log.notice(`QR Code URL: https://project-chip.github.io/connectedhomeip/qrcode.html?data=${qrPairingCode}`);
1931
1368
  this.log.notice(`Manual pairing code: ${manualPairingCode}`);
1369
+ if (this.matterStorageService) {
1370
+ const storageManager = await this.matterStorageService.open(storeId);
1371
+ const storageContext = storageManager.createContext('persist');
1372
+ await storageContext.set('qrPairingCode', qrPairingCode);
1373
+ await storageContext.set('manualPairingCode', manualPairingCode);
1374
+ }
1932
1375
  }
1933
1376
  if (this.bridgeMode === 'childbridge') {
1934
1377
  const plugin = this.plugins.get(storeId);
1935
1378
  if (plugin) {
1936
1379
  plugin.qrPairingCode = qrPairingCode;
1937
1380
  plugin.manualPairingCode = manualPairingCode;
1938
- plugin.fabricInformations = [];
1939
- plugin.sessionInformations = [];
1381
+ plugin.fabricInformations = undefined;
1382
+ plugin.sessionInformations = undefined;
1940
1383
  plugin.paired = false;
1941
1384
  this.log.notice(`QR Code URL: https://project-chip.github.io/connectedhomeip/qrcode.html?data=${qrPairingCode}`);
1942
1385
  this.log.notice(`Manual pairing code: ${manualPairingCode}`);
1386
+ if (this.matterStorageService) {
1387
+ const storageManager = await this.matterStorageService.open(storeId);
1388
+ const storageContext = storageManager.createContext('persist');
1389
+ await storageContext.set('qrPairingCode', qrPairingCode);
1390
+ await storageContext.set('manualPairingCode', manualPairingCode);
1391
+ }
1943
1392
  }
1944
1393
  }
1945
1394
  }
@@ -1949,32 +1398,27 @@ export class Matterbridge extends EventEmitter {
1949
1398
  }
1950
1399
  this.frontend.wssSendRefreshRequired();
1951
1400
  });
1952
- /** This event is triggered when the device went offline. it is not longer discoverable or connectable in the network. */
1953
1401
  serverNode.lifecycle.offline.on(() => {
1954
1402
  this.log.notice(`Server node for ${storeId} is offline`);
1955
1403
  if (this.bridgeMode === 'bridge') {
1956
1404
  this.matterbridgeQrPairingCode = undefined;
1957
1405
  this.matterbridgeManualPairingCode = undefined;
1958
- this.matterbridgeFabricInformations = [];
1959
- this.matterbridgeSessionInformations = [];
1960
- this.matterbridgePaired = false;
1406
+ this.matterbridgeFabricInformations = undefined;
1407
+ this.matterbridgeSessionInformations = undefined;
1408
+ this.matterbridgePaired = undefined;
1961
1409
  }
1962
1410
  if (this.bridgeMode === 'childbridge') {
1963
1411
  const plugin = this.plugins.get(storeId);
1964
1412
  if (plugin) {
1965
1413
  plugin.qrPairingCode = undefined;
1966
1414
  plugin.manualPairingCode = undefined;
1967
- plugin.fabricInformations = [];
1968
- plugin.sessionInformations = [];
1969
- plugin.paired = false;
1415
+ plugin.fabricInformations = undefined;
1416
+ plugin.sessionInformations = undefined;
1417
+ plugin.paired = undefined;
1970
1418
  }
1971
1419
  }
1972
1420
  this.frontend.wssSendRefreshRequired();
1973
1421
  });
1974
- /**
1975
- * This event is triggered when a fabric is added, removed or updated on the device. Use this if more granular
1976
- * information is needed.
1977
- */
1978
1422
  serverNode.events.commissioning.fabricsChanged.on((fabricIndex, fabricAction) => {
1979
1423
  let action = '';
1980
1424
  switch (fabricAction) {
@@ -2008,24 +1452,16 @@ export class Matterbridge extends EventEmitter {
2008
1452
  }
2009
1453
  }
2010
1454
  };
2011
- /**
2012
- * This event is triggered when an operative new session was opened by a Controller.
2013
- * It is not triggered for the initial commissioning process, just afterwards for real connections.
2014
- */
2015
1455
  serverNode.events.sessions.opened.on((session) => {
2016
1456
  this.log.notice(`Session opened on server node for ${storeId}: ${debugStringify(session)}`);
2017
1457
  sanitizeSessions(Object.values(serverNode.state.sessions.sessions));
2018
1458
  this.frontend.wssSendRefreshRequired();
2019
1459
  });
2020
- /**
2021
- * This event is triggered when an operative session is closed by a Controller or because the Device goes offline.
2022
- */
2023
1460
  serverNode.events.sessions.closed.on((session) => {
2024
1461
  this.log.notice(`Session closed on server node for ${storeId}: ${debugStringify(session)}`);
2025
1462
  sanitizeSessions(Object.values(serverNode.state.sessions.sessions));
2026
1463
  this.frontend.wssSendRefreshRequired();
2027
1464
  });
2028
- /** This event is triggered when a subscription gets added or removed on an operative session. */
2029
1465
  serverNode.events.sessions.subscriptionsChanged.on((session) => {
2030
1466
  this.log.notice(`Session subscriptions changed on server node for ${storeId}: ${debugStringify(session)}`);
2031
1467
  sanitizeSessions(Object.values(serverNode.state.sessions.sessions));
@@ -2045,6 +1481,16 @@ export class Matterbridge extends EventEmitter {
2045
1481
  return;
2046
1482
  this.log.notice(`Closing ${matterServerNode.id} server node`);
2047
1483
  await matterServerNode.close();
1484
+ await matterServerNode.env.get(MdnsService)[Symbol.asyncDispose]();
1485
+ }
1486
+ async advertiseServerNode(matterServerNode) {
1487
+ if (matterServerNode && matterServerNode.lifecycle.isCommissioned) {
1488
+ await matterServerNode.env.get(DeviceCommissioner)?.allowBasicCommissioning();
1489
+ const { qrPairingCode, manualPairingCode } = matterServerNode.state.commissioning.pairingCodes;
1490
+ this.log.notice(`Advertising for ${matterServerNode.id} is now started with the following pairing codes: qrPairingCode ${qrPairingCode}, manualPairingCode ${manualPairingCode}`);
1491
+ return { qrPairingCode, manualPairingCode };
1492
+ }
1493
+ return undefined;
2048
1494
  }
2049
1495
  async createAggregatorNode(storageContext) {
2050
1496
  this.log.notice(`Creating ${await storageContext.get('storeId')} aggregator `);
@@ -2052,13 +1498,11 @@ export class Matterbridge extends EventEmitter {
2052
1498
  return aggregatorNode;
2053
1499
  }
2054
1500
  async addBridgedEndpoint(pluginName, device) {
2055
- // Check if the plugin is registered
2056
1501
  const plugin = this.plugins.get(pluginName);
2057
1502
  if (!plugin) {
2058
1503
  this.log.error(`Error adding bridged endpoint ${dev}${device.deviceName}${er} (${zb}${device.id}${er}) plugin ${plg}${pluginName}${er} not found`);
2059
1504
  return;
2060
1505
  }
2061
- // Register and add the device to the matterbridge aggregator node
2062
1506
  if (this.bridgeMode === 'bridge') {
2063
1507
  this.log.debug(`Adding bridged endpoint ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} to Matterbridge aggregator node`);
2064
1508
  if (!this.aggregatorNode)
@@ -2081,19 +1525,16 @@ export class Matterbridge extends EventEmitter {
2081
1525
  plugin.registeredDevices++;
2082
1526
  if (plugin.addedDevices !== undefined)
2083
1527
  plugin.addedDevices++;
2084
- // Add the device to the DeviceManager
2085
1528
  this.devices.set(device);
2086
1529
  this.log.info(`Added and registered bridged endpoint (${plugin.registeredDevices}/${plugin.addedDevices}) ${dev}${device.deviceName}${nf} (${dev}${device.id}${nf}) for plugin ${plg}${pluginName}${nf}`);
2087
1530
  }
2088
1531
  async removeBridgedEndpoint(pluginName, device) {
2089
1532
  this.log.debug(`Removing bridged endpoint ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} (${zb}${device.name}${db}) for plugin ${plg}${pluginName}${db}`);
2090
- // Check if the plugin is registered
2091
1533
  const plugin = this.plugins.get(pluginName);
2092
1534
  if (!plugin) {
2093
1535
  this.log.error(`Error removing bridged endpoint ${dev}${device.deviceName}${er} (${zb}${device.name}${er}) for plugin ${plg}${pluginName}${er}: plugin not found`);
2094
1536
  return;
2095
1537
  }
2096
- // Register and add the device to the matterbridge aggregator node
2097
1538
  if (this.bridgeMode === 'bridge') {
2098
1539
  if (!this.aggregatorNode) {
2099
1540
  this.log.error(`Error removing bridged endpoint ${dev}${device.deviceName}${er} (${zb}${device.name}${er}) for plugin ${plg}${pluginName}${er}: aggregator node not found`);
@@ -2108,7 +1549,6 @@ export class Matterbridge extends EventEmitter {
2108
1549
  }
2109
1550
  else if (this.bridgeMode === 'childbridge') {
2110
1551
  if (plugin.type === 'AccessoryPlatform') {
2111
- // Nothing to do here since the server node has no aggregator node but only the device itself
2112
1552
  }
2113
1553
  else if (plugin.type === 'DynamicPlatform') {
2114
1554
  if (!plugin.aggregatorNode) {
@@ -2122,7 +1562,6 @@ export class Matterbridge extends EventEmitter {
2122
1562
  plugin.registeredDevices--;
2123
1563
  if (plugin.addedDevices !== undefined)
2124
1564
  plugin.addedDevices--;
2125
- // Close the server node TODO check if this is correct
2126
1565
  if (plugin.registeredDevices === 0 && plugin.addedDevices === 0) {
2127
1566
  if (plugin.serverNode) {
2128
1567
  await this.stopServerNode(plugin.serverNode);
@@ -2133,7 +1572,6 @@ export class Matterbridge extends EventEmitter {
2133
1572
  }
2134
1573
  }
2135
1574
  }
2136
- // Remove the device from the DeviceManager
2137
1575
  this.devices.remove(device);
2138
1576
  }
2139
1577
  async removeAllBridgedEndpoints(pluginName) {
@@ -2142,12 +1580,6 @@ export class Matterbridge extends EventEmitter {
2142
1580
  await this.removeBridgedEndpoint(pluginName, device);
2143
1581
  }
2144
1582
  }
2145
- /**
2146
- * Sanitizes the fabric information by converting bigint properties to string cause res.json doesn't know bigint.
2147
- *
2148
- * @param fabricInfo - The array of exposed fabric information objects.
2149
- * @returns An array of sanitized exposed fabric information objects.
2150
- */
2151
1583
  sanitizeFabricInformations(fabricInfo) {
2152
1584
  return fabricInfo.map((info) => {
2153
1585
  return {
@@ -2161,12 +1593,6 @@ export class Matterbridge extends EventEmitter {
2161
1593
  };
2162
1594
  });
2163
1595
  }
2164
- /**
2165
- * Sanitizes the session information by converting bigint properties to string.
2166
- *
2167
- * @param sessionInfo - The array of session information objects.
2168
- * @returns An array of sanitized session information objects.
2169
- */
2170
1596
  sanitizeSessionInformation(sessionInfo) {
2171
1597
  return sessionInfo
2172
1598
  .filter((session) => session.isPeerActive)
@@ -2194,51 +1620,11 @@ export class Matterbridge extends EventEmitter {
2194
1620
  };
2195
1621
  });
2196
1622
  }
2197
- /**
2198
- * Sets the reachability of a matter server node and trigger ReachableChanged event.
2199
- *
2200
- * @param {ServerNode<ServerNode.RootEndpoint>} serverNode - The commissioning server to set the reachability for.
2201
- * @param {boolean} reachable - The new reachability status.
2202
- */
2203
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
2204
1623
  setServerNodeReachability(serverNode, reachable) {
2205
- /*
2206
- const basicInformationCluster = commissioningServer?.getRootClusterServer(BasicInformationCluster);
2207
- if (basicInformationCluster && basicInformationCluster.attributes.reachable !== undefined) basicInformationCluster.setReachableAttribute(reachable);
2208
- if (basicInformationCluster && basicInformationCluster.triggerReachableChangedEvent) basicInformationCluster.triggerReachableChangedEvent({ reachableNewValue: reachable });
2209
- */
2210
1624
  }
2211
- /**
2212
- * Sets the reachability of the specified matter aggregator and its bridged devices and trigger.
2213
- * @param {EndpointNode<AggregatorEndpoint>} aggregatorNode - The matter aggregator to set the reachability for.
2214
- * @param {boolean} reachable - A boolean indicating the reachability status to set.
2215
- */
2216
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
2217
1625
  setAggregatorReachability(aggregatorNode, reachable) {
2218
- /*
2219
- const basicInformationCluster = matterAggregator.getClusterServer(BasicInformationCluster);
2220
- if (basicInformationCluster && basicInformationCluster.attributes.reachable !== undefined) basicInformationCluster.setReachableAttribute(reachable);
2221
- if (basicInformationCluster && basicInformationCluster.triggerReachableChangedEvent) basicInformationCluster.triggerReachableChangedEvent({ reachableNewValue: reachable });
2222
- matterAggregator.getBridgedDevices().forEach((device) => {
2223
- this.log.debug(`Setting reachability to true for bridged device: ${dev}${device.name}${nf}`);
2224
- device.getClusterServer(BridgedDeviceBasicInformationCluster)?.setReachableAttribute(reachable);
2225
- device.getClusterServer(BridgedDeviceBasicInformationCluster)?.triggerReachableChangedEvent({ reachableNewValue: reachable });
2226
- });
2227
- */
2228
1626
  }
2229
- /**
2230
- * Sets the reachability of a device and trigger.
2231
- *
2232
- * @param {MatterbridgeEndpoint} device - The device to set the reachability for.
2233
- * @param {boolean} reachable - The new reachability status of the device.
2234
- */
2235
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
2236
1627
  setDeviceReachability(device, reachable) {
2237
- /*
2238
- const basicInformationCluster = device.getClusterServer(BasicInformationCluster);
2239
- if (basicInformationCluster && basicInformationCluster.attributes.reachable !== undefined) basicInformationCluster.setReachableAttribute(reachable);
2240
- if (basicInformationCluster && basicInformationCluster.triggerReachableChangedEvent) basicInformationCluster.triggerReachableChangedEvent({ reachableNewValue: reachable });
2241
- */
2242
1628
  }
2243
1629
  getVendorIdName = (vendorId) => {
2244
1630
  if (!vendorId)
@@ -2281,36 +1667,13 @@ export class Matterbridge extends EventEmitter {
2281
1667
  }
2282
1668
  return vendorName;
2283
1669
  };
2284
- /**
2285
- * Spawns a child process with the given command and arguments.
2286
- * @param {string} command - The command to execute.
2287
- * @param {string[]} args - The arguments to pass to the command (default: []).
2288
- * @returns {Promise<boolean>} A promise that resolves when the child process exits successfully, or rejects if there is an error.
2289
- */
2290
1670
  async spawnCommand(command, args = []) {
2291
- /*
2292
- npm > npm.cmd on windows
2293
- cmd.exe ['dir'] on windows
2294
- await this.spawnCommand('npm', ['install', '-g', 'matterbridge']);
2295
- process.on('unhandledRejection', (reason, promise) => {
2296
- this.log.error('Unhandled Rejection at:', promise, 'reason:', reason);
2297
- });
2298
-
2299
- spawn - [14:27:21.125] [Matterbridge:spawn]: changed 38 packages in 4s
2300
- spawn - [14:27:21.125] [Matterbridge:spawn]: 10 packages are looking for funding run `npm fund` for details
2301
- debug - [14:27:21.131] [Matterbridge]: Child process exited with code 0 and signal null
2302
- debug - [14:27:21.131] [Matterbridge]: Child process stdio streams have closed with code 0
2303
- */
2304
1671
  const cmdLine = command + ' ' + args.join(' ');
2305
1672
  if (process.platform === 'win32' && command === 'npm') {
2306
- // Must be spawn('cmd.exe', ['/c', 'npm -g install <package>']);
2307
1673
  const argstring = 'npm ' + args.join(' ');
2308
1674
  args.splice(0, args.length, '/c', argstring);
2309
1675
  command = 'cmd.exe';
2310
1676
  }
2311
- // Decide when using sudo on linux
2312
- // When you need sudo: Spawn stderr: npm error Error: EACCES: permission denied
2313
- // When you don't need sudo: Failed to start child process "npm install -g matterbridge-eve-door": spawn sudo ENOENT
2314
1677
  if (hasParameter('sudo') || (process.platform === 'linux' && command === 'npm' && !hasParameter('docker') && !hasParameter('nosudo'))) {
2315
1678
  args.unshift(command);
2316
1679
  command = 'sudo';
@@ -2369,4 +1732,3 @@ export class Matterbridge extends EventEmitter {
2369
1732
  });
2370
1733
  }
2371
1734
  }
2372
- //# sourceMappingURL=matterbridge.js.map