matterbridge 1.6.0 → 1.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (148) hide show
  1. package/CHANGELOG.md +53 -1
  2. package/README-DEV.md +0 -4
  3. package/README-NGINX.md +63 -0
  4. package/README.md +8 -0
  5. package/dist/cli.d.ts +1 -1
  6. package/dist/cli.js +18 -8
  7. package/dist/cli.js.map +1 -1
  8. package/dist/defaultConfigSchema.d.ts +1 -1
  9. package/dist/defaultConfigSchema.js +1 -1
  10. package/dist/deviceManager.d.ts +2 -2
  11. package/dist/deviceManager.d.ts.map +1 -1
  12. package/dist/deviceManager.js +2 -2
  13. package/dist/deviceManager.js.map +1 -1
  14. package/dist/index.d.ts +10 -10
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +24 -11
  17. package/dist/index.js.map +1 -1
  18. package/dist/matter/export.d.ts +5 -0
  19. package/dist/matter/export.d.ts.map +1 -0
  20. package/dist/matter/export.js +5 -0
  21. package/dist/matter/export.js.map +1 -0
  22. package/dist/matterbridge.d.ts +32 -16
  23. package/dist/matterbridge.d.ts.map +1 -1
  24. package/dist/matterbridge.js +254 -115
  25. package/dist/matterbridge.js.map +1 -1
  26. package/dist/matterbridgeAccessoryPlatform.d.ts +1 -1
  27. package/dist/matterbridgeAccessoryPlatform.d.ts.map +1 -1
  28. package/dist/matterbridgeAccessoryPlatform.js +1 -1
  29. package/dist/matterbridgeAccessoryPlatform.js.map +1 -1
  30. package/dist/matterbridgeBehaviors.d.ts +1123 -0
  31. package/dist/matterbridgeBehaviors.d.ts.map +1 -0
  32. package/dist/matterbridgeBehaviors.js +281 -0
  33. package/dist/matterbridgeBehaviors.js.map +1 -0
  34. package/dist/matterbridgeDevice.d.ts +2069 -1511
  35. package/dist/matterbridgeDevice.d.ts.map +1 -1
  36. package/dist/matterbridgeDevice.js +192 -196
  37. package/dist/matterbridgeDevice.js.map +1 -1
  38. package/dist/matterbridgeDeviceTypes.d.ts +58 -0
  39. package/dist/matterbridgeDeviceTypes.d.ts.map +1 -0
  40. package/dist/matterbridgeDeviceTypes.js +308 -0
  41. package/dist/matterbridgeDeviceTypes.js.map +1 -0
  42. package/dist/matterbridgeDynamicPlatform.d.ts +1 -1
  43. package/dist/matterbridgeDynamicPlatform.d.ts.map +1 -1
  44. package/dist/matterbridgeDynamicPlatform.js +1 -1
  45. package/dist/matterbridgeDynamicPlatform.js.map +1 -1
  46. package/dist/matterbridgeEdge.d.ts +20 -21
  47. package/dist/matterbridgeEdge.d.ts.map +1 -1
  48. package/dist/matterbridgeEdge.js +506 -103
  49. package/dist/matterbridgeEdge.js.map +1 -1
  50. package/dist/matterbridgeEndpoint.d.ts +3545 -2336
  51. package/dist/matterbridgeEndpoint.d.ts.map +1 -1
  52. package/dist/matterbridgeEndpoint.js +672 -468
  53. package/dist/matterbridgeEndpoint.js.map +1 -1
  54. package/dist/matterbridgePlatform.d.ts +5 -4
  55. package/dist/matterbridgePlatform.d.ts.map +1 -1
  56. package/dist/matterbridgePlatform.js +11 -3
  57. package/dist/matterbridgePlatform.js.map +1 -1
  58. package/dist/matterbridgeTypes.d.ts +7 -8
  59. package/dist/matterbridgeTypes.d.ts.map +1 -1
  60. package/dist/matterbridgeTypes.js.map +1 -1
  61. package/dist/matterbridgeWebsocket.d.ts +1 -1
  62. package/dist/matterbridgeWebsocket.d.ts.map +1 -1
  63. package/dist/matterbridgeWebsocket.js +41 -3
  64. package/dist/matterbridgeWebsocket.js.map +1 -1
  65. package/dist/pluginManager.d.ts +1 -1
  66. package/dist/pluginManager.d.ts.map +1 -1
  67. package/dist/pluginManager.js +17 -8
  68. package/dist/pluginManager.js.map +1 -1
  69. package/dist/utils/colorUtils.d.ts +1 -1
  70. package/dist/utils/colorUtils.js +2 -2
  71. package/dist/utils/colorUtils.js.map +1 -1
  72. package/dist/utils/utils.d.ts +42 -1
  73. package/dist/utils/utils.d.ts.map +1 -1
  74. package/dist/utils/utils.js +105 -3
  75. package/dist/utils/utils.js.map +1 -1
  76. package/frontend/build/asset-manifest.json +62 -6
  77. package/frontend/build/index.html +1 -1
  78. package/frontend/build/static/css/main.823e08b6.css +2 -0
  79. package/frontend/build/static/css/main.823e08b6.css.map +1 -0
  80. package/frontend/build/static/js/main.a14c87e7.js +115 -0
  81. package/frontend/build/static/js/{main.045d08f7.js.LICENSE.txt → main.a14c87e7.js.LICENSE.txt} +3 -3
  82. package/frontend/build/static/js/main.a14c87e7.js.map +1 -0
  83. package/frontend/build/static/media/roboto-cyrillic-300-normal.1b79538ccd585c259996.woff2 +0 -0
  84. package/frontend/build/static/media/roboto-cyrillic-300-normal.5f077fd7b977d1715acf.woff +0 -0
  85. package/frontend/build/static/media/roboto-cyrillic-400-normal.5d2930082227d172f62c.woff +0 -0
  86. package/frontend/build/static/media/roboto-cyrillic-400-normal.a9e19870cf6c4b973427.woff2 +0 -0
  87. package/frontend/build/static/media/roboto-cyrillic-500-normal.0ae2428323939af5e1ad.woff2 +0 -0
  88. package/frontend/build/static/media/roboto-cyrillic-500-normal.dd7bc8a52c6c70c5a3f5.woff +0 -0
  89. package/frontend/build/static/media/roboto-cyrillic-700-normal.3f6e1548bd5175a8c342.woff +0 -0
  90. package/frontend/build/static/media/roboto-cyrillic-700-normal.4fdfc29a10e7d4b7c527.woff2 +0 -0
  91. package/frontend/build/static/media/roboto-cyrillic-ext-300-normal.795dbc8140e3fef82983.woff +0 -0
  92. package/frontend/build/static/media/roboto-cyrillic-ext-300-normal.80947a31d23c70204b47.woff2 +0 -0
  93. package/frontend/build/static/media/roboto-cyrillic-ext-400-normal.135d076fa32aa0b4d105.woff +0 -0
  94. package/frontend/build/static/media/roboto-cyrillic-ext-400-normal.5cec61a21cc20180fbe1.woff2 +0 -0
  95. package/frontend/build/static/media/roboto-cyrillic-ext-500-normal.6de16332fda843a3dc3d.woff2 +0 -0
  96. package/frontend/build/static/media/roboto-cyrillic-ext-500-normal.c0a0638f90b31d6454ba.woff +0 -0
  97. package/frontend/build/static/media/roboto-cyrillic-ext-700-normal.4750292c47fa2bc6ac1a.woff2 +0 -0
  98. package/frontend/build/static/media/roboto-cyrillic-ext-700-normal.ca247189fc12d00de361.woff +0 -0
  99. package/frontend/build/static/media/roboto-greek-300-normal.285f3e6261d8eb20417d.woff2 +0 -0
  100. package/frontend/build/static/media/roboto-greek-300-normal.889beddda1c9bd9f97df.woff +0 -0
  101. package/frontend/build/static/media/roboto-greek-400-normal.160a791a8e4f46bca3cc.woff +0 -0
  102. package/frontend/build/static/media/roboto-greek-400-normal.2c32b1315be61477013a.woff2 +0 -0
  103. package/frontend/build/static/media/roboto-greek-500-normal.60810e07c7b0273013aa.woff +0 -0
  104. package/frontend/build/static/media/roboto-greek-500-normal.f95e757c5483310f9c11.woff2 +0 -0
  105. package/frontend/build/static/media/roboto-greek-700-normal.77dd370f2001e184ba0d.woff2 +0 -0
  106. package/frontend/build/static/media/roboto-greek-700-normal.df87b053fae3d7ad5f7a.woff +0 -0
  107. package/frontend/build/static/media/roboto-greek-ext-300-normal.b590dbe5c639944366d1.woff +0 -0
  108. package/frontend/build/static/media/roboto-greek-ext-300-normal.d6049cb54aa6fbe14c42.woff2 +0 -0
  109. package/frontend/build/static/media/roboto-greek-ext-400-normal.16eb83b4a3b1ea994243.woff +0 -0
  110. package/frontend/build/static/media/roboto-greek-ext-400-normal.1df4abad55796d11a0c8.woff2 +0 -0
  111. package/frontend/build/static/media/roboto-greek-ext-500-normal.4a96ba31abcce0f5d52b.woff2 +0 -0
  112. package/frontend/build/static/media/roboto-greek-ext-500-normal.fd28d9c008bf3af1bed7.woff +0 -0
  113. package/frontend/build/static/media/roboto-greek-ext-700-normal.2dd6febad11502dec6a6.woff2 +0 -0
  114. package/frontend/build/static/media/roboto-greek-ext-700-normal.4abdc9fff4507f17d726.woff +0 -0
  115. package/frontend/build/static/media/roboto-latin-300-normal.b850f1ff581ea232fac9.woff2 +0 -0
  116. package/frontend/build/static/media/roboto-latin-300-normal.c4bc0593c9954d79cb3a.woff +0 -0
  117. package/frontend/build/static/media/roboto-latin-400-normal.047a7839f69b209db815.woff +0 -0
  118. package/frontend/build/static/media/roboto-latin-400-normal.297d48e1b5a10c0831a9.woff2 +0 -0
  119. package/frontend/build/static/media/roboto-latin-500-normal.68d40d6d01c6f85d24ba.woff +0 -0
  120. package/frontend/build/static/media/roboto-latin-500-normal.7077203b1982951ecf76.woff2 +0 -0
  121. package/frontend/build/static/media/roboto-latin-700-normal.4535474e1cf8598695ad.woff2 +0 -0
  122. package/frontend/build/static/media/roboto-latin-700-normal.9f6a16a7770c87b2042b.woff +0 -0
  123. package/frontend/build/static/media/roboto-latin-ext-300-normal.14982a9e4857a93b6dce.woff +0 -0
  124. package/frontend/build/static/media/roboto-latin-ext-300-normal.97cbc447d4a8d41a9543.woff2 +0 -0
  125. package/frontend/build/static/media/roboto-latin-ext-400-normal.27da5b36b6d3a16f53f4.woff +0 -0
  126. package/frontend/build/static/media/roboto-latin-ext-400-normal.2eeae187764baf05867d.woff2 +0 -0
  127. package/frontend/build/static/media/roboto-latin-ext-500-normal.06c30711d588145a4541.woff +0 -0
  128. package/frontend/build/static/media/roboto-latin-ext-500-normal.9a18d7bb9ff7a6af7b32.woff2 +0 -0
  129. package/frontend/build/static/media/roboto-latin-ext-700-normal.18841836e391d39e83a8.woff2 +0 -0
  130. package/frontend/build/static/media/roboto-latin-ext-700-normal.3c5bcdd0e69c4c3ffafe.woff +0 -0
  131. package/frontend/build/static/media/roboto-vietnamese-300-normal.c96b16e5c05c7b7c3e89.woff2 +0 -0
  132. package/frontend/build/static/media/roboto-vietnamese-300-normal.f5e7cea32756dfe7af40.woff +0 -0
  133. package/frontend/build/static/media/roboto-vietnamese-400-normal.0dc97c66f9b542d6fa17.woff +0 -0
  134. package/frontend/build/static/media/roboto-vietnamese-400-normal.d3f8e26d6c27de8102b6.woff2 +0 -0
  135. package/frontend/build/static/media/roboto-vietnamese-500-normal.090fabef926bdc0e9b9f.woff2 +0 -0
  136. package/frontend/build/static/media/roboto-vietnamese-500-normal.23b7b8a2524d2d4b637b.woff +0 -0
  137. package/frontend/build/static/media/roboto-vietnamese-700-normal.0a79a9fabfc32e33f360.woff2 +0 -0
  138. package/frontend/build/static/media/roboto-vietnamese-700-normal.35ed0597568ff6f19c16.woff +0 -0
  139. package/npm-shrinkwrap.json +120 -39
  140. package/package.json +8 -3
  141. package/dist/matterbridgeController.d.ts +0 -24
  142. package/dist/matterbridgeController.d.ts.map +0 -1
  143. package/dist/matterbridgeController.js +0 -386
  144. package/dist/matterbridgeController.js.map +0 -1
  145. package/frontend/build/static/css/main.1cf003ae.css +0 -2
  146. package/frontend/build/static/css/main.1cf003ae.css.map +0 -1
  147. package/frontend/build/static/js/main.045d08f7.js +0 -3
  148. package/frontend/build/static/js/main.045d08f7.js.map +0 -1
@@ -25,32 +25,32 @@ import { fileURLToPath } from 'url';
25
25
  import { promises as fs } from 'fs';
26
26
  import { exec, spawn } from 'child_process';
27
27
  import { createServer } from 'http';
28
- import https from 'https';
29
28
  import EventEmitter from 'events';
30
- import express from 'express';
31
29
  import os from 'os';
32
30
  import path from 'path';
31
+ import { randomBytes } from 'crypto';
32
+ // Package modules
33
+ import https from 'https';
34
+ import express from 'express';
33
35
  import WebSocket, { WebSocketServer } from 'ws';
34
36
  // NodeStorage and AnsiLogger modules
35
37
  import { NodeStorageManager } from 'node-persist-manager';
36
- import { AnsiLogger, UNDERLINE, UNDERLINEOFF, YELLOW, db, debugStringify, stringify, BRIGHT, RESET, er, nf, rs, wr, RED, GREEN, zb, hk, or, idn, BLUE, CYAN, nt } from 'node-ansi-logger';
38
+ import { AnsiLogger, UNDERLINE, UNDERLINEOFF, YELLOW, db, debugStringify, stringify, BRIGHT, RESET, er, nf, rs, wr, RED, GREEN, zb, CYAN, nt, idn, or, hk, BLUE } from 'node-ansi-logger';
37
39
  // Matterbridge
38
40
  import { MatterbridgeDevice } from './matterbridgeDevice.js';
39
- import { logInterfaces, wait, waiter, createZip } from './utils/utils.js';
41
+ import { WS_ID_LOG, WS_ID_REFRESH_NEEDED, WS_ID_RESTART_NEEDED, wsMessageHandler } from './matterbridgeWebsocket.js';
42
+ import { logInterfaces, wait, waiter, createZip, copyDirectory, getParameter, getIntParameter, hasParameter } from './utils/utils.js';
40
43
  import { PluginManager } from './pluginManager.js';
41
44
  import { DeviceManager } from './deviceManager.js';
42
- // @project-chip/matter-node.js
43
- import { CommissioningController, CommissioningServer, MatterServer } from '@project-chip/matter-node.js';
44
- import { BasicInformationCluster, BridgedDeviceBasicInformation, BridgedDeviceBasicInformationCluster, ClusterServer, FixedLabelCluster, GeneralCommissioning, PowerSourceCluster, SwitchCluster, ThreadNetworkDiagnosticsCluster, getClusterNameById, } from '@project-chip/matter-node.js/cluster';
45
- import { DeviceTypeId, VendorId } from '@project-chip/matter-node.js/datatype';
46
- import { Aggregator, DeviceTypes, NodeStateInformation } from '@project-chip/matter-node.js/device';
47
- import { Format, Level, Logger } from '@project-chip/matter-node.js/log';
48
- import { ManualPairingCodeCodec, QrCodeSchema } from '@project-chip/matter-node.js/schema';
49
- import { StorageBackendDisk, StorageBackendJsonFile, StorageManager } from '@project-chip/matter-node.js/storage';
50
- import { getParameter, getIntParameter, hasParameter } from '@project-chip/matter-node.js/util';
51
- import { CryptoNode } from '@project-chip/matter-node.js/crypto';
52
- import { Specification } from '@project-chip/matter-node.js/model';
53
- import { WS_ID_LOG, WS_ID_REFRESH_NEEDED, WS_ID_RESTART_NEEDED, wsMessageHandler } from './matterbridgeWebsocket.js';
45
+ import { MatterbridgeEndpoint } from './matterbridgeEndpoint.js';
46
+ // @matter
47
+ import { DeviceTypeId, Logger, LogLevel as MatterLogLevel, LogFormat as MatterLogFormat, VendorId, StorageManager } from '@matter/main';
48
+ import { BasicInformationCluster, BridgedDeviceBasicInformation, BridgedDeviceBasicInformationCluster, FixedLabelCluster, GeneralCommissioning, PowerSourceCluster, SwitchCluster, ThreadNetworkDiagnosticsCluster } from '@matter/main/clusters';
49
+ import { getClusterNameById, ManualPairingCodeCodec, QrCodeSchema } from '@matter/main/types';
50
+ import { StorageBackendDisk, StorageBackendJsonFile } from '@matter/nodejs';
51
+ // @project-chip
52
+ import { CommissioningController, CommissioningServer, MatterServer } from '@project-chip/matter.js';
53
+ import { Aggregator, DeviceTypes, NodeStateInformation } from '@project-chip/matter.js/device';
54
54
  // Default colors
55
55
  const plg = '\u001B[38;5;33m';
56
56
  const dev = '\u001B[38;5;79m';
@@ -91,9 +91,11 @@ export class Matterbridge extends EventEmitter {
91
91
  matterbridgeConnected: false,
92
92
  bridgeMode: '',
93
93
  restartMode: '',
94
+ edge: hasParameter('edge'),
95
+ profile: getParameter('profile'),
94
96
  loggerLevel: "info" /* LogLevel.INFO */,
95
97
  fileLogger: false,
96
- matterLoggerLevel: Level.INFO,
98
+ matterLoggerLevel: MatterLogLevel.INFO,
97
99
  matterFileLogger: false,
98
100
  mattermdnsinterface: undefined,
99
101
  matteripv4address: undefined,
@@ -117,6 +119,7 @@ export class Matterbridge extends EventEmitter {
117
119
  bridgeMode = '';
118
120
  restartMode = '';
119
121
  profile = getParameter('profile');
122
+ edge = hasParameter('edge');
120
123
  log;
121
124
  matterbrideLoggerFile = 'matterbridge' + (getParameter('profile') ? '.' + getParameter('profile') : '') + '.log';
122
125
  matterLoggerFile = 'matter' + (getParameter('profile') ? '.' + getParameter('profile') : '') + '.log';
@@ -136,6 +139,8 @@ export class Matterbridge extends EventEmitter {
136
139
  reachabilityTimeout;
137
140
  sigintHandler;
138
141
  sigtermHandler;
142
+ exceptionHandler;
143
+ rejectionHandler;
139
144
  // Frontend
140
145
  expressApp;
141
146
  httpServer;
@@ -155,6 +160,8 @@ export class Matterbridge extends EventEmitter {
155
160
  matterAggregator;
156
161
  commissioningServer;
157
162
  commissioningController;
163
+ aggregatorVendorId = VendorId(getIntParameter('vendorId') ?? 0xfff1);
164
+ aggregatorProductId = getIntParameter('productId') ?? 0x8000;
158
165
  static instance;
159
166
  // We load asyncronously so is private
160
167
  constructor() {
@@ -221,19 +228,54 @@ export class Matterbridge extends EventEmitter {
221
228
  // Set the matterbridge directory
222
229
  this.homeDirectory = getParameter('homedir') ?? os.homedir();
223
230
  this.matterbridgeDirectory = path.join(this.homeDirectory, '.matterbridge');
224
- // Initialize nodeStorage and nodeContext
225
- // this.log.debug(`Creating node storage manager: ${CYAN}${this.nodeStorageName}${db}`);
226
- this.nodeStorage = new NodeStorageManager({ dir: path.join(this.matterbridgeDirectory, this.nodeStorageName), writeQueue: false, expiredInterval: undefined, logging: false });
227
- // this.log.debug('Creating node storage context for matterbridge');
228
- this.nodeContext = await this.nodeStorage.createStorage('matterbridge');
229
- // Check if the storage is corrupted and remove it
230
- // TODO: Check if the storage is corrupted and remove it
231
231
  // Create matterbridge logger
232
- this.log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: "info" /* LogLevel.INFO */ });
233
- // Create the file logger for matterbridge (context: matterbridgeFileLog)
234
- if (hasParameter('filelogger') || (await this.nodeContext.get('matterbridgeFileLog', false))) {
235
- AnsiLogger.setGlobalLogfile(path.join(this.matterbridgeDirectory, this.matterbrideLoggerFile), "debug" /* LogLevel.DEBUG */, true);
236
- this.matterbridgeInformation.fileLogger = true;
232
+ this.log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: hasParameter('debug') ? "debug" /* LogLevel.DEBUG */ : "info" /* LogLevel.INFO */ });
233
+ // Initialize nodeStorage and nodeContext
234
+ try {
235
+ this.log.debug(`Creating node storage manager: ${CYAN}${this.nodeStorageName}${db}`);
236
+ this.nodeStorage = new NodeStorageManager({ dir: path.join(this.matterbridgeDirectory, this.nodeStorageName), writeQueue: false, expiredInterval: undefined, logging: false });
237
+ this.log.debug('Creating node storage context for matterbridge');
238
+ this.nodeContext = await this.nodeStorage.createStorage('matterbridge');
239
+ // TODO: Remove this code when node-persist-manager is updated
240
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
241
+ const keys = (await this.nodeStorage?.storage.keys());
242
+ for (const key of keys) {
243
+ this.log.debug(`Checking node storage manager key: ${CYAN}${key}${db}`);
244
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
245
+ await this.nodeStorage?.storage.get(key);
246
+ }
247
+ const storages = await this.nodeStorage.getStorageNames();
248
+ for (const storage of storages) {
249
+ this.log.debug(`Checking storage: ${CYAN}${storage}${db}`);
250
+ const nodeContext = await this.nodeStorage?.createStorage(storage);
251
+ // TODO: Remove this code when node-persist-manager is updated
252
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
253
+ const keys = (await nodeContext?.storage.keys());
254
+ keys.forEach(async (key) => {
255
+ this.log.debug(`Checking key: ${CYAN}${storage}:${key}${db}`);
256
+ await nodeContext?.get(key);
257
+ });
258
+ }
259
+ // Creating a backup of the node storage since it is not corrupted
260
+ this.log.debug('Creating node storage backup...');
261
+ await copyDirectory(path.join(this.matterbridgeDirectory, this.nodeStorageName), path.join(this.matterbridgeDirectory, this.nodeStorageName + '.backup'));
262
+ this.log.debug('Created node storage backup');
263
+ }
264
+ catch (error) {
265
+ // Restoring the backup of the node storage since it is corrupted
266
+ this.log.error(`Error creating node storage manager and context: ${error instanceof Error ? error.message : error}`);
267
+ if (hasParameter('norestore')) {
268
+ this.log.fatal(`The matterbridge node storage is corrupted. Parameter -norestore found: exiting...`);
269
+ await this.cleanup('Fatal error creating node storage manager and context for matterbridge');
270
+ return;
271
+ }
272
+ this.log.notice(`The matterbridge storage is corrupted. Restoring it with backup...`);
273
+ await copyDirectory(path.join(this.matterbridgeDirectory, this.nodeStorageName + '.backup'), path.join(this.matterbridgeDirectory, this.nodeStorageName));
274
+ this.log.notice(`The matterbridge storage has been restored with backup`);
275
+ }
276
+ if (!this.nodeStorage || !this.nodeContext) {
277
+ this.log.fatal('Fatal error creating node storage manager and context for matterbridge');
278
+ throw new Error('Fatal error creating node storage manager and context for matterbridge');
237
279
  }
238
280
  // Set matterbridge logger level (context: matterbridgeLogLevel)
239
281
  if (hasParameter('logger')) {
@@ -265,45 +307,50 @@ export class Matterbridge extends EventEmitter {
265
307
  this.log.logLevel = await this.nodeContext.get('matterbridgeLogLevel', "info" /* LogLevel.INFO */);
266
308
  }
267
309
  MatterbridgeDevice.logLevel = this.log.logLevel;
310
+ // Create the file logger for matterbridge (context: matterbridgeFileLog)
311
+ if (hasParameter('filelogger') || (await this.nodeContext.get('matterbridgeFileLog', false))) {
312
+ AnsiLogger.setGlobalLogfile(path.join(this.matterbridgeDirectory, this.matterbrideLoggerFile), this.log.logLevel, true);
313
+ this.matterbridgeInformation.fileLogger = true;
314
+ }
268
315
  this.log.notice('Matterbridge is starting...');
269
316
  this.log.debug(`Matterbridge logLevel: ${this.log.logLevel} fileLoger: ${this.matterbridgeInformation.fileLogger}.`);
270
317
  // Set matter.js logger level, format and logger (context: matterLogLevel)
271
318
  if (hasParameter('matterlogger')) {
272
319
  const level = getParameter('matterlogger');
273
320
  if (level === 'debug') {
274
- Logger.defaultLogLevel = Level.DEBUG;
321
+ Logger.defaultLogLevel = MatterLogLevel.DEBUG;
275
322
  }
276
323
  else if (level === 'info') {
277
- Logger.defaultLogLevel = Level.INFO;
324
+ Logger.defaultLogLevel = MatterLogLevel.INFO;
278
325
  }
279
326
  else if (level === 'notice') {
280
- Logger.defaultLogLevel = Level.NOTICE;
327
+ Logger.defaultLogLevel = MatterLogLevel.NOTICE;
281
328
  }
282
329
  else if (level === 'warn') {
283
- Logger.defaultLogLevel = Level.WARN;
330
+ Logger.defaultLogLevel = MatterLogLevel.WARN;
284
331
  }
285
332
  else if (level === 'error') {
286
- Logger.defaultLogLevel = Level.ERROR;
333
+ Logger.defaultLogLevel = MatterLogLevel.ERROR;
287
334
  }
288
335
  else if (level === 'fatal') {
289
- Logger.defaultLogLevel = Level.FATAL;
336
+ Logger.defaultLogLevel = MatterLogLevel.FATAL;
290
337
  }
291
338
  else {
292
339
  this.log.warn(`Invalid matter.js logger level: ${level}. Using default level "info".`);
293
- Logger.defaultLogLevel = Level.INFO;
340
+ Logger.defaultLogLevel = MatterLogLevel.INFO;
294
341
  }
295
342
  }
296
343
  else {
297
- Logger.defaultLogLevel = await this.nodeContext.get('matterLogLevel', Level.INFO);
344
+ Logger.defaultLogLevel = await this.nodeContext.get('matterLogLevel', MatterLogLevel.INFO);
298
345
  }
299
- Logger.format = Format.ANSI;
346
+ Logger.format = MatterLogFormat.ANSI;
300
347
  Logger.setLogger('default', this.createMatterLogger());
301
348
  // Create the file logger for matter.js (context: matterFileLog)
302
349
  if (hasParameter('matterfilelogger') || (await this.nodeContext.get('matterFileLog', false))) {
303
350
  this.matterbridgeInformation.matterFileLogger = true;
304
351
  Logger.addLogger('matterfilelogger', await this.createMatterFileLogger(path.join(this.matterbridgeDirectory, this.matterLoggerFile), true), {
305
- defaultLogLevel: Level.DEBUG,
306
- logFormat: Format.PLAIN,
352
+ defaultLogLevel: Logger.defaultLogLevel,
353
+ logFormat: MatterLogFormat.PLAIN,
307
354
  });
308
355
  }
309
356
  this.log.debug(`Matter logLevel: ${Logger.defaultLogLevel} fileLoger: ${this.matterbridgeInformation.matterFileLogger}.`);
@@ -347,7 +394,7 @@ export class Matterbridge extends EventEmitter {
347
394
  // We don't do this when the add parameter is set because we shut down the process after adding the plugin
348
395
  this.log.info(`Error parsing plugin ${plg}${plugin.name}${nf}. Trying to reinstall it from npm.`);
349
396
  try {
350
- await this.spawnCommand('npm', ['install', '-g', '--omit=dev', plugin.name]);
397
+ await this.spawnCommand('npm', ['install', '-g', plugin.name, '--omit=dev', '--verbose']);
351
398
  this.log.info(`Plugin ${plg}${plugin.name}${nf} reinstalled.`);
352
399
  plugin.error = false;
353
400
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
@@ -383,8 +430,8 @@ export class Matterbridge extends EventEmitter {
383
430
  this.log.error(`Node version ${versionMajor} is not supported. Please upgrade to ${minNodeVersion} or above.`);
384
431
  throw new Error(`Node version ${versionMajor} is not supported. Please upgrade to ${minNodeVersion} or above.`);
385
432
  }
386
- // Register SIGINT SIGTERM signal handlers
387
- this.registerSignalHandlers();
433
+ // Register process handlers
434
+ this.registerProcessHandlers();
388
435
  // Parse command line
389
436
  await this.parseCommandLine();
390
437
  this.initialized = true;
@@ -415,6 +462,7 @@ export class Matterbridge extends EventEmitter {
415
462
  - logstorage: log the node storage
416
463
  - sudo: force the use of sudo to install or update packages if the internal logic fails
417
464
  - nosudo: force not to use sudo to install or update packages if the internal logic fails
465
+ - norestore: force not to automatically restore the matterbridge node storage and the matter storage from backup if it is corrupted
418
466
  - ssl: enable SSL for the frontend and WebSockerServer (certificates in .matterbridge/certs directory cert.pem, key.pem and ca.pem (optional))
419
467
  - add [plugin path]: register the plugin from the given absolute or relative path
420
468
  - add [plugin name]: register the globally installed plugin with the given name
@@ -522,7 +570,13 @@ export class Matterbridge extends EventEmitter {
522
570
  return;
523
571
  }
524
572
  // Start the matter storage and create the matterbridge context
525
- await this.startMatterStorage('json', path.join(this.matterbridgeDirectory, this.matterStorageName));
573
+ try {
574
+ await this.startMatterStorage('json', path.join(this.matterbridgeDirectory, this.matterStorageName));
575
+ }
576
+ catch (error) {
577
+ this.log.fatal(`Fatal error creating matter storage: ${error instanceof Error ? error.message : error}`);
578
+ throw new Error(`Fatal error creating matter storage: ${error instanceof Error ? error.message : error}`);
579
+ }
526
580
  if (hasParameter('reset') && getParameter('reset') === undefined) {
527
581
  this.log.info('Resetting Matterbridge commissioning information...');
528
582
  await this.matterbridgeContext?.clearAll();
@@ -581,6 +635,7 @@ export class Matterbridge extends EventEmitter {
581
635
  if (hasParameter('bridge') || (!hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'bridge')) {
582
636
  this.bridgeMode = 'bridge';
583
637
  MatterbridgeDevice.bridgeMode = 'bridge';
638
+ MatterbridgeEndpoint.bridgeMode = 'bridge';
584
639
  this.log.debug(`Starting matterbridge in mode ${this.bridgeMode}`);
585
640
  await this.startBridge();
586
641
  return;
@@ -589,6 +644,7 @@ export class Matterbridge extends EventEmitter {
589
644
  if (hasParameter('childbridge') || (!hasParameter('bridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'childbridge')) {
590
645
  this.bridgeMode = 'childbridge';
591
646
  MatterbridgeDevice.bridgeMode = 'childbridge';
647
+ MatterbridgeEndpoint.bridgeMode = 'childbridge';
592
648
  this.log.debug(`Starting matterbridge in mode ${this.bridgeMode}`);
593
649
  await this.startChildbridge();
594
650
  return;
@@ -635,10 +691,23 @@ export class Matterbridge extends EventEmitter {
635
691
  this.wssSendRefreshRequired();
636
692
  }
637
693
  /**
638
- * Registers the signal handlers for SIGINT and SIGTERM.
694
+ * Registers the process handlers for uncaughtException, unhandledRejection, SIGINT and SIGTERM.
639
695
  * When either of these signals are received, the cleanup method is called with an appropriate message.
640
696
  */
641
- registerSignalHandlers() {
697
+ registerProcessHandlers() {
698
+ this.log.debug(`Registering uncaughtException and unhandledRejection handlers...`);
699
+ process.removeAllListeners('uncaughtException');
700
+ process.removeAllListeners('unhandledRejection');
701
+ this.exceptionHandler = async (error) => {
702
+ this.log.fatal('Unhandled Exception detected at:', error.stack || error, rs);
703
+ // await this.cleanup('Unhandled Exception detected, cleaning up...');
704
+ };
705
+ process.on('uncaughtException', this.exceptionHandler);
706
+ this.rejectionHandler = async (reason, promise) => {
707
+ this.log.fatal('Unhandled Rejection detected at:', promise, 'reason:', reason instanceof Error ? reason.stack : reason, rs);
708
+ // await this.cleanup('Unhandled Rejection detected, cleaning up...');
709
+ };
710
+ process.on('unhandledRejection', this.rejectionHandler);
642
711
  this.log.debug(`Registering SIGINT and SIGTERM signal handlers...`);
643
712
  this.sigintHandler = async () => {
644
713
  await this.cleanup('SIGINT received, cleaning up...');
@@ -650,9 +719,16 @@ export class Matterbridge extends EventEmitter {
650
719
  process.on('SIGTERM', this.sigtermHandler);
651
720
  }
652
721
  /**
653
- * Deregisters the SIGINT and SIGTERM signal handlers.
722
+ * Deregisters the process uncaughtException, unhandledRejection, SIGINT and SIGTERM signal handlers.
654
723
  */
655
- deregisterSignalHandlers() {
724
+ deregisterProcesslHandlers() {
725
+ this.log.debug(`Deregistering uncaughtException and unhandledRejection handlers...`);
726
+ if (this.exceptionHandler)
727
+ process.off('uncaughtException', this.exceptionHandler);
728
+ this.exceptionHandler = undefined;
729
+ if (this.rejectionHandler)
730
+ process.off('unhandledRejection', this.rejectionHandler);
731
+ this.rejectionHandler = undefined;
656
732
  this.log.debug(`Deregistering SIGINT and SIGTERM signal handlers...`);
657
733
  if (this.sigintHandler)
658
734
  process.off('SIGINT', this.sigintHandler);
@@ -922,22 +998,22 @@ export class Matterbridge extends EventEmitter {
922
998
  const message = formattedLog.slice(65);
923
999
  matterLogger.logName = logger;
924
1000
  switch (_level) {
925
- case Level.DEBUG:
1001
+ case MatterLogLevel.DEBUG:
926
1002
  matterLogger.log("debug" /* LogLevel.DEBUG */, message);
927
1003
  break;
928
- case Level.INFO:
1004
+ case MatterLogLevel.INFO:
929
1005
  matterLogger.log("info" /* LogLevel.INFO */, message);
930
1006
  break;
931
- case Level.NOTICE:
1007
+ case MatterLogLevel.NOTICE:
932
1008
  matterLogger.log("notice" /* LogLevel.NOTICE */, message);
933
1009
  break;
934
- case Level.WARN:
1010
+ case MatterLogLevel.WARN:
935
1011
  matterLogger.log("warn" /* LogLevel.WARN */, message);
936
1012
  break;
937
- case Level.ERROR:
1013
+ case MatterLogLevel.ERROR:
938
1014
  matterLogger.log("error" /* LogLevel.ERROR */, message);
939
1015
  break;
940
- case Level.FATAL:
1016
+ case MatterLogLevel.FATAL:
941
1017
  matterLogger.log("fatal" /* LogLevel.FATAL */, message);
942
1018
  break;
943
1019
  default:
@@ -979,22 +1055,22 @@ export class Matterbridge extends EventEmitter {
979
1055
  const logger = parts[1];
980
1056
  const finalMessage = parts.slice(2).join(' ') + os.EOL;
981
1057
  switch (_level) {
982
- case Level.DEBUG:
1058
+ case MatterLogLevel.DEBUG:
983
1059
  await fs.appendFile(filePath, `[${timestamp}] [${logger}] [debug] ${finalMessage}`);
984
1060
  break;
985
- case Level.INFO:
1061
+ case MatterLogLevel.INFO:
986
1062
  await fs.appendFile(filePath, `[${timestamp}] [${logger}] [info] ${finalMessage}`);
987
1063
  break;
988
- case Level.NOTICE:
1064
+ case MatterLogLevel.NOTICE:
989
1065
  await fs.appendFile(filePath, `[${timestamp}] [${logger}] [notice] ${finalMessage}`);
990
1066
  break;
991
- case Level.WARN:
1067
+ case MatterLogLevel.WARN:
992
1068
  await fs.appendFile(filePath, `[${timestamp}] [${logger}] [warn] ${finalMessage}`);
993
1069
  break;
994
- case Level.ERROR:
1070
+ case MatterLogLevel.ERROR:
995
1071
  await fs.appendFile(filePath, `[${timestamp}] [${logger}] [error] ${finalMessage}`);
996
1072
  break;
997
- case Level.FATAL:
1073
+ case MatterLogLevel.FATAL:
998
1074
  await fs.appendFile(filePath, `[${timestamp}] [${logger}] [fatal] ${finalMessage}`);
999
1075
  break;
1000
1076
  default:
@@ -1053,8 +1129,8 @@ export class Matterbridge extends EventEmitter {
1053
1129
  if (this.initialized && !this.hasCleanupStarted) {
1054
1130
  this.hasCleanupStarted = true;
1055
1131
  this.log.info(message);
1056
- // Deregisters the SIGINT and SIGTERM signal handlers
1057
- this.deregisterSignalHandlers();
1132
+ // Deregisters the process handlers
1133
+ this.deregisterProcesslHandlers();
1058
1134
  // Clear the start matter interval
1059
1135
  if (this.startMatterInterval) {
1060
1136
  clearInterval(this.startMatterInterval);
@@ -1209,6 +1285,18 @@ export class Matterbridge extends EventEmitter {
1209
1285
  this.initialized = false;
1210
1286
  }
1211
1287
  }
1288
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1289
+ async addBridgedEndpoint(pluginName, device) {
1290
+ // Nothing to do here
1291
+ }
1292
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1293
+ async removeBridgedEndpoint(pluginName, device) {
1294
+ // Nothing to do here
1295
+ }
1296
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1297
+ async removeAllBridgedEndpoints(pluginName) {
1298
+ // Nothing to do here
1299
+ }
1212
1300
  /**
1213
1301
  * Adds a bridged device to the Matterbridge.
1214
1302
  * @param pluginName - The name of the plugin.
@@ -1717,7 +1805,7 @@ export class Matterbridge extends EventEmitter {
1717
1805
  * @returns {Promise<void>} - A promise that resolves when the storage process is started.
1718
1806
  */
1719
1807
  async startMatterStorage(storageType, storageName) {
1720
- this.log.debug(`Starting ${storageType} storage ${CYAN}${storageName}${db}`);
1808
+ this.log.debug(`Starting matter ${storageType} storage ${CYAN}${storageName}${db}`);
1721
1809
  if (storageType === 'disk') {
1722
1810
  const storageDisk = new StorageBackendDisk(storageName);
1723
1811
  this.storageManager = new StorageManager(storageDisk);
@@ -1729,22 +1817,34 @@ export class Matterbridge extends EventEmitter {
1729
1817
  this.storageManager = new StorageManager(storageJson);
1730
1818
  }
1731
1819
  else {
1732
- this.log.error(`Unsupported storage type ${storageType}`);
1733
- await this.cleanup('Unsupported storage type');
1820
+ this.log.error(`Unsupported matter storage type ${storageType}`);
1821
+ await this.cleanup('Unsupported matter storage type');
1734
1822
  return;
1735
1823
  }
1736
1824
  try {
1737
1825
  await this.storageManager.initialize();
1738
- this.log.debug('Storage initialized');
1826
+ this.log.debug('Matter storage initialized');
1739
1827
  if (storageType === 'json') {
1740
1828
  await this.backupMatterStorage(storageName, storageName.replace('.json', '') + '.backup.json');
1741
1829
  }
1742
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1743
1830
  }
1744
1831
  catch (error) {
1745
- this.log.error(`Storage initialize() error! The file .matterbridge/${storageName} may be corrupted.`);
1746
- this.log.error(`Please delete it and rename ${storageName.replace('.json', '.backup.json')} to ${storageName} and try to restart Matterbridge.`);
1747
- await this.cleanup('Storage initialize() error!');
1832
+ this.log.error(`Matter storage initialize error! The file .matterbridge/${storageName} may be corrupted: ${error instanceof Error ? error.message : error}`);
1833
+ if (hasParameter('norestore')) {
1834
+ this.log.fatal(`Please delete it and rename ${storageName.replace('.json', '.backup.json')} to ${storageName} and try to restart Matterbridge.`);
1835
+ await this.cleanup('Matter storage initialize error and -norestore parameter found!');
1836
+ return;
1837
+ }
1838
+ await this.restoreMatterStorage(storageName.replace('.json', '') + '.backup.json', storageName);
1839
+ try {
1840
+ await this.storageManager.initialize();
1841
+ this.log.notice('Matter storage initialized from the backup file');
1842
+ }
1843
+ catch (error) {
1844
+ this.log.error(`Matter storage initialize error! The backup file for .matterbridge/${storageName} may be corrupted too:`, error instanceof Error ? error.message : error);
1845
+ await this.cleanup('Matter storage initialize error from backup!');
1846
+ return;
1847
+ }
1748
1848
  }
1749
1849
  this.log.debug(`Creating commissioning server context for ${plg}Matterbridge${db}`);
1750
1850
  this.matterbridgeContext = await this.createCommissioningServerContext('Matterbridge', 'Matterbridge', DeviceTypes.AGGREGATOR.code, 0xfff1, 'Matterbridge', 0x8000, 'Matterbridge aggregator');
@@ -1764,7 +1864,7 @@ export class Matterbridge extends EventEmitter {
1764
1864
  catch (err) {
1765
1865
  if (err instanceof Error && 'code' in err) {
1766
1866
  if (err.code === 'ENOENT') {
1767
- this.log.info(`No existing file to back up for ${storageName}. This is expected on the first run.`);
1867
+ this.log.debug(`No existing file to back up for ${storageName}. This is expected on the first run.`);
1768
1868
  }
1769
1869
  else {
1770
1870
  this.log.error(`Error making backup copy of ${storageName}: ${err.message}`);
@@ -1775,6 +1875,32 @@ export class Matterbridge extends EventEmitter {
1775
1875
  }
1776
1876
  }
1777
1877
  }
1878
+ /**
1879
+ * Restore the specified matter JSON storage file.
1880
+ *
1881
+ * @param backupName - The name of the backup file to restore from.
1882
+ * @param storageName - The name of the JSON storage file to restored.
1883
+ */
1884
+ async restoreMatterStorage(backupName, storageName) {
1885
+ try {
1886
+ this.log.notice(`Restoring the backup copy of ${storageName}`);
1887
+ await fs.copyFile(backupName, storageName);
1888
+ this.log.notice(`Successfully restored ${backupName} to ${storageName}`);
1889
+ }
1890
+ catch (err) {
1891
+ if (err instanceof Error && 'code' in err) {
1892
+ if (err.code === 'ENOENT') {
1893
+ this.log.info(`No existing file to restore: ${backupName}.`);
1894
+ }
1895
+ else {
1896
+ this.log.error(`Error restoring ${backupName}: ${err.message}`);
1897
+ }
1898
+ }
1899
+ else {
1900
+ this.log.error(`An unexpected error occurred during the restore of ${backupName}: ${String(err)}`);
1901
+ }
1902
+ }
1903
+ }
1778
1904
  /**
1779
1905
  * Stops the matter storage.
1780
1906
  * @returns {Promise<void>} A promise that resolves when the storage is stopped.
@@ -1846,39 +1972,52 @@ export class Matterbridge extends EventEmitter {
1846
1972
  * @param {StorageContext} context - The storage context.
1847
1973
  * @returns {Aggregator} - The created Matter Aggregator.
1848
1974
  */
1975
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1849
1976
  async createMatterAggregator(context, pluginName) {
1850
- const random = 'AG' + CryptoNode.getRandomData(8).toHex();
1977
+ /*
1978
+ const random = randomBytes(8).toString('hex');
1851
1979
  await context.set('aggregatorSerialNumber', await context.get('aggregatorSerialNumber', random));
1852
1980
  await context.set('aggregatorUniqueId', await context.get('aggregatorUniqueId', random));
1853
- this.log.debug(`Creating matter aggregator for plugin ${plg}${pluginName}${db} with uniqueId ${await context.get('aggregatorUniqueId')} serialNumber ${await context.get('aggregatorSerialNumber')}`);
1854
- this.log.debug(`Creating matter aggregator for plugin ${plg}${pluginName}${db} with softwareVersion ${await context.get('softwareVersion', 1)} softwareVersionString ${await context.get('softwareVersionString', '1.0.0')}`);
1855
- this.log.debug(`Creating matter aggregator for plugin ${plg}${pluginName}${db} with hardwareVersion ${await context.get('hardwareVersion', 1)} hardwareVersionString ${await context.get('hardwareVersionString', '1.0.0')}`);
1981
+
1982
+ this.log.debug(`Creating matter aggregator for plugin ${plg}${pluginName}${db} with uniqueId ${await context.get<string>('aggregatorUniqueId')} serialNumber ${await context.get<string>('aggregatorSerialNumber')}`);
1983
+ this.log.debug(`Creating matter aggregator for plugin ${plg}${pluginName}${db} with softwareVersion ${await context.get<number>('softwareVersion', 1)} softwareVersionString ${await context.get<string>('softwareVersionString', '1.0.0')}`);
1984
+ this.log.debug(`Creating matter aggregator for plugin ${plg}${pluginName}${db} with hardwareVersion ${await context.get<number>('hardwareVersion', 1)} hardwareVersionString ${await context.get<string>('hardwareVersionString', '1.0.0')}`);
1985
+ */
1856
1986
  const matterAggregator = new Aggregator();
1857
- matterAggregator.addClusterServer(ClusterServer(BasicInformationCluster, {
1858
- dataModelRevision: 1,
1859
- location: 'FR',
1860
- vendorId: VendorId(0xfff1),
1861
- vendorName: 'Matterbridge',
1862
- productId: 0x8000,
1863
- productName: 'Matterbridge aggregator',
1864
- productLabel: 'Matterbridge aggregator',
1865
- nodeLabel: 'Matterbridge aggregator',
1866
- serialNumber: await context.get('aggregatorSerialNumber'),
1867
- uniqueId: await context.get('aggregatorUniqueId'),
1868
- softwareVersion: await context.get('softwareVersion', 1),
1869
- softwareVersionString: await context.get('softwareVersionString', '1.0.0'),
1870
- hardwareVersion: await context.get('hardwareVersion', 1),
1871
- hardwareVersionString: await context.get('hardwareVersionString', '1.0.0'),
1872
- reachable: true,
1873
- capabilityMinima: { caseSessionsPerFabric: 3, subscriptionsPerFabric: 3 },
1874
- specificationVersion: Specification.SPECIFICATION_VERSION,
1875
- maxPathsPerInvoke: 1,
1876
- }, {}, {
1877
- startUp: true,
1878
- shutDown: true,
1879
- leave: true,
1880
- reachableChanged: true,
1881
- }));
1987
+ /*
1988
+ matterAggregator.addClusterServer(
1989
+ ClusterServer(
1990
+ BasicInformationCluster,
1991
+ {
1992
+ dataModelRevision: 1,
1993
+ location: 'FR',
1994
+ vendorId: VendorId(0xfff1),
1995
+ vendorName: 'Matterbridge',
1996
+ productId: 0x8000,
1997
+ productName: 'Matterbridge aggregator',
1998
+ productLabel: 'Matterbridge aggregator',
1999
+ nodeLabel: 'Matterbridge aggregator',
2000
+ serialNumber: await context.get<string>('aggregatorSerialNumber'),
2001
+ uniqueId: await context.get<string>('aggregatorUniqueId'),
2002
+ softwareVersion: await context.get<number>('softwareVersion', 1),
2003
+ softwareVersionString: await context.get<string>('softwareVersionString', '1.0.0'),
2004
+ hardwareVersion: await context.get<number>('hardwareVersion', 1),
2005
+ hardwareVersionString: await context.get<string>('hardwareVersionString', '1.0.0'),
2006
+ reachable: true,
2007
+ capabilityMinima: { caseSessionsPerFabric: 3, subscriptionsPerFabric: 3 },
2008
+ specificationVersion: Specification.SPECIFICATION_VERSION,
2009
+ maxPathsPerInvoke: 1,
2010
+ },
2011
+ {},
2012
+ {
2013
+ startUp: true,
2014
+ shutDown: true,
2015
+ leave: true,
2016
+ reachableChanged: true,
2017
+ },
2018
+ ),
2019
+ );
2020
+ */
1882
2021
  return matterAggregator;
1883
2022
  }
1884
2023
  /**
@@ -2071,7 +2210,7 @@ export class Matterbridge extends EventEmitter {
2071
2210
  if (!this.storageManager)
2072
2211
  throw new Error('No storage manager initialized');
2073
2212
  this.log.debug(`Creating commissioning server storage context for ${plg}${pluginName}${db}`);
2074
- const random = 'CS' + CryptoNode.getRandomData(8).toHex();
2213
+ const random = randomBytes(8).toString('hex');
2075
2214
  const storageContext = this.storageManager.createContext(pluginName);
2076
2215
  await storageContext.set('deviceName', deviceName);
2077
2216
  await storageContext.set('deviceType', deviceType);
@@ -2376,7 +2515,7 @@ export class Matterbridge extends EventEmitter {
2376
2515
  * Spawns a child process with the given command and arguments.
2377
2516
  * @param {string} command - The command to execute.
2378
2517
  * @param {string[]} args - The arguments to pass to the command (default: []).
2379
- * @returns {Promise<void>} A promise that resolves when the child process exits successfully, or rejects if there is an error.
2518
+ * @returns {Promise<boolean>} A promise that resolves when the child process exits successfully, or rejects if there is an error.
2380
2519
  */
2381
2520
  async spawnCommand(command, args = []) {
2382
2521
  /*
@@ -2421,7 +2560,7 @@ export class Matterbridge extends EventEmitter {
2421
2560
  if (cmdLine.startsWith('npm install -g'))
2422
2561
  this.log.notice(`Package ${cmdLine.replace('npm install -g ', '').replace('--verbose', '').replace('--omit=dev', '')} installed correctly`);
2423
2562
  this.log.debug(`Child process "${cmdLine}" closed with code ${code} and signal ${signal}`);
2424
- resolve();
2563
+ resolve(true);
2425
2564
  }
2426
2565
  else {
2427
2566
  this.log.error(`Child process "${cmdLine}" closed with code ${code} and signal ${signal}`);
@@ -2432,7 +2571,7 @@ export class Matterbridge extends EventEmitter {
2432
2571
  this.wssSendMessage('spawn', this.log.now(), 'Matterbridge:spawn', `child process exited with code ${code} and signal ${signal}`);
2433
2572
  if (code === 0) {
2434
2573
  this.log.debug(`Child process "${cmdLine}" exited with code ${code} and signal ${signal}`);
2435
- resolve();
2574
+ resolve(true);
2436
2575
  }
2437
2576
  else {
2438
2577
  this.log.error(`Child process "${cmdLine}" exited with code ${code} and signal ${signal}`);
@@ -2441,7 +2580,7 @@ export class Matterbridge extends EventEmitter {
2441
2580
  });
2442
2581
  childProcess.on('disconnect', () => {
2443
2582
  this.log.debug(`Child process "${cmdLine}" has been disconnected from the parent`);
2444
- resolve();
2583
+ resolve(true);
2445
2584
  });
2446
2585
  if (childProcess.stdout) {
2447
2586
  childProcess.stdout.on('data', (data) => {
@@ -3013,22 +3152,22 @@ export class Matterbridge extends EventEmitter {
3013
3152
  if (command === 'setmjloglevel') {
3014
3153
  this.log.debug('Matter.js log level:', param);
3015
3154
  if (param === 'Debug') {
3016
- Logger.defaultLogLevel = Level.DEBUG;
3155
+ Logger.defaultLogLevel = MatterLogLevel.DEBUG;
3017
3156
  }
3018
3157
  else if (param === 'Info') {
3019
- Logger.defaultLogLevel = Level.INFO;
3158
+ Logger.defaultLogLevel = MatterLogLevel.INFO;
3020
3159
  }
3021
3160
  else if (param === 'Notice') {
3022
- Logger.defaultLogLevel = Level.NOTICE;
3161
+ Logger.defaultLogLevel = MatterLogLevel.NOTICE;
3023
3162
  }
3024
3163
  else if (param === 'Warn') {
3025
- Logger.defaultLogLevel = Level.WARN;
3164
+ Logger.defaultLogLevel = MatterLogLevel.WARN;
3026
3165
  }
3027
3166
  else if (param === 'Error') {
3028
- Logger.defaultLogLevel = Level.ERROR;
3167
+ Logger.defaultLogLevel = MatterLogLevel.ERROR;
3029
3168
  }
3030
3169
  else if (param === 'Fatal') {
3031
- Logger.defaultLogLevel = Level.FATAL;
3170
+ Logger.defaultLogLevel = MatterLogLevel.FATAL;
3032
3171
  }
3033
3172
  await this.nodeContext?.set('matterLogLevel', Logger.defaultLogLevel);
3034
3173
  res.json({ message: 'Command received' });
@@ -3082,8 +3221,8 @@ export class Matterbridge extends EventEmitter {
3082
3221
  if (param === 'true') {
3083
3222
  try {
3084
3223
  Logger.addLogger('matterfilelogger', await this.createMatterFileLogger(path.join(this.matterbridgeDirectory, this.matterLoggerFile), true), {
3085
- defaultLogLevel: Level.DEBUG,
3086
- logFormat: Format.PLAIN,
3224
+ defaultLogLevel: MatterLogLevel.DEBUG,
3225
+ logFormat: MatterLogFormat.PLAIN,
3087
3226
  });
3088
3227
  }
3089
3228
  catch (error) {
@@ -3371,8 +3510,8 @@ export class Matterbridge extends EventEmitter {
3371
3510
  await this.logNodeAndSystemInfo();
3372
3511
  this.matterbridgeDirectory = dataPath;
3373
3512
  // Set matter.js logger level and format
3374
- Logger.defaultLogLevel = Level.INFO;
3375
- Logger.format = Format.ANSI;
3513
+ Logger.defaultLogLevel = MatterLogLevel.INFO;
3514
+ Logger.format = MatterLogFormat.ANSI;
3376
3515
  // Start the storage and create matterbridgeContext
3377
3516
  await this.startMatterStorage('json', path.join(this.matterbridgeDirectory, this.matterStorageName));
3378
3517
  if (!this.storageManager)