matterbridge 2.0.0-edge1 → 2.1.0-dev.1

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