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
package/dist/frontend.js CHANGED
@@ -1,28 +1,4 @@
1
- /**
2
- * This file contains the class Frontend.
3
- *
4
- * @file frontend.ts
5
- * @author Luca Liguori
6
- * @date 2025-01-13
7
- * @version 1.0.0
8
- *
9
- * Copyright 2025, 2026, 2027 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
- // @matter
24
1
  import { EndpointServer, Logger, LogLevel as MatterLogLevel, LogFormat as MatterLogFormat } from '@matter/main';
25
- // Node modules
26
2
  import { createServer } from 'http';
27
3
  import https from 'https';
28
4
  import express from 'express';
@@ -30,32 +6,13 @@ import WebSocket, { WebSocketServer } from 'ws';
30
6
  import os from 'os';
31
7
  import path from 'path';
32
8
  import { promises as fs } from 'fs';
33
- // AnsiLogger module
34
- import { AnsiLogger, CYAN, db, debugStringify, er, LogLevel, nf, rs, stringify, TimestampFormat, UNDERLINE, UNDERLINEOFF, wr, YELLOW } from 'node-ansi-logger';
35
- // Matterbridge
9
+ import { AnsiLogger, CYAN, db, debugStringify, er, nf, rs, stringify, UNDERLINE, UNDERLINEOFF, wr, YELLOW } from './logger/export.js';
36
10
  import { createZip, hasParameter, isValidNumber, isValidObject, isValidString } from './utils/utils.js';
37
11
  import { plg } from './matterbridgeTypes.js';
38
12
  import { MatterbridgeEndpoint } from './matterbridgeEndpoint.js';
39
- /**
40
- * Websocket message ID for logging.
41
- * @constant {number}
42
- */
43
13
  export const WS_ID_LOG = 0;
44
- /**
45
- * Websocket message ID indicating a refresh is needed.
46
- * @constant {number}
47
- */
48
14
  export const WS_ID_REFRESH_NEEDED = 1;
49
- /**
50
- * Websocket message ID indicating a restart is needed.
51
- * @constant {number}
52
- */
53
15
  export const WS_ID_RESTART_NEEDED = 2;
54
- /**
55
- * Initializes the frontend of Matterbridge.
56
- *
57
- * @param port The port number to run the frontend server on. Default is 8283.
58
- */
59
16
  export class Frontend {
60
17
  matterbridge;
61
18
  log;
@@ -67,26 +24,15 @@ export class Frontend {
67
24
  webSocketServer;
68
25
  constructor(matterbridge) {
69
26
  this.matterbridge = matterbridge;
70
- this.log = new AnsiLogger({ logName: 'Frontend', logTimestampFormat: TimestampFormat.TIME_MILLIS, logLevel: hasParameter('debug') ? LogLevel.DEBUG : LogLevel.INFO });
27
+ this.log = new AnsiLogger({ logName: 'Frontend', logTimestampFormat: 4, logLevel: hasParameter('debug') ? "debug" : "info" });
71
28
  }
72
29
  async start(port = 8283) {
73
30
  this.port = port;
74
31
  this.log.debug(`Initializing the frontend ${hasParameter('ssl') ? 'https' : 'http'} server on port ${YELLOW}${this.port}${db}`);
75
- // Create the express app that serves the frontend
76
32
  this.expressApp = express();
77
- // Log all requests to the server for debugging
78
- /*
79
- this.expressApp.use((req, res, next) => {
80
- this.log.debug(`Received request on expressApp: ${req.method} ${req.url}`);
81
- next();
82
- });
83
- */
84
- // Serve static files from '/static' endpoint
85
33
  this.expressApp.use(express.static(path.join(this.matterbridge.rootDirectory, 'frontend/build')));
86
34
  if (!hasParameter('ssl')) {
87
- // Create an HTTP server and attach the express app
88
35
  this.httpServer = createServer(this.expressApp);
89
- // Listen on the specified port
90
36
  if (hasParameter('ingress')) {
91
37
  this.httpServer.listen(this.port, '0.0.0.0', () => {
92
38
  this.log.info(`The frontend http server is listening on ${UNDERLINE}http://0.0.0.0:${this.port}${UNDERLINEOFF}${rs}`);
@@ -100,7 +46,6 @@ export class Frontend {
100
46
  this.log.info(`The frontend http server is listening on ${UNDERLINE}http://[${this.matterbridge.systemInformation.ipv6Address}]:${this.port}${UNDERLINEOFF}${rs}`);
101
47
  });
102
48
  }
103
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
104
49
  this.httpServer.on('error', (error) => {
105
50
  this.log.error(`Frontend http server error listening on ${this.port}`);
106
51
  switch (error.code) {
@@ -116,7 +61,6 @@ export class Frontend {
116
61
  });
117
62
  }
118
63
  else {
119
- // Load the SSL certificate, the private key and optionally the CA certificate
120
64
  let cert;
121
65
  try {
122
66
  cert = await fs.readFile(path.join(this.matterbridge.matterbridgeDirectory, 'certs/cert.pem'), 'utf8');
@@ -144,9 +88,7 @@ export class Frontend {
144
88
  this.log.info(`CA certificate file ${path.join(this.matterbridge.matterbridgeDirectory, 'certs/ca.pem')} not loaded: ${error}`);
145
89
  }
146
90
  const serverOptions = { cert, key, ca };
147
- // Create an HTTPS server with the SSL certificate and private key (ca is optional) and attach the express app
148
91
  this.httpsServer = https.createServer(serverOptions, this.expressApp);
149
- // Listen on the specified port
150
92
  if (hasParameter('ingress')) {
151
93
  this.httpsServer.listen(this.port, '0.0.0.0', () => {
152
94
  this.log.info(`The frontend https server is listening on ${UNDERLINE}https://0.0.0.0:${this.port}${UNDERLINEOFF}${rs}`);
@@ -160,7 +102,6 @@ export class Frontend {
160
102
  this.log.info(`The frontend https server is listening on ${UNDERLINE}https://[${this.matterbridge.systemInformation.ipv6Address}]:${this.port}${UNDERLINEOFF}${rs}`);
161
103
  });
162
104
  }
163
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
164
105
  this.httpsServer.on('error', (error) => {
165
106
  this.log.error(`Frontend https server error listening on ${this.port}`);
166
107
  switch (error.code) {
@@ -177,13 +118,12 @@ export class Frontend {
177
118
  }
178
119
  if (this.initializeError)
179
120
  return;
180
- // Createe a WebSocket server and attach it to the http or https server
181
121
  const wssPort = this.port;
182
122
  const wssHost = hasParameter('ssl') ? `wss://${this.matterbridge.systemInformation.ipv4Address}:${wssPort}` : `ws://${this.matterbridge.systemInformation.ipv4Address}:${wssPort}`;
183
123
  this.webSocketServer = new WebSocketServer(hasParameter('ssl') ? { server: this.httpsServer } : { server: this.httpServer });
184
124
  this.webSocketServer.on('connection', (ws, request) => {
185
125
  const clientIp = request.socket.remoteAddress;
186
- AnsiLogger.setGlobalCallback(this.wssSendMessage.bind(this), LogLevel.DEBUG);
126
+ AnsiLogger.setGlobalCallback(this.wssSendMessage.bind(this), "debug");
187
127
  this.log.info(`WebSocketServer client "${clientIp}" connected to Matterbridge`);
188
128
  ws.on('message', (message) => {
189
129
  this.wsMessageHandler(ws, message);
@@ -215,7 +155,6 @@ export class Frontend {
215
155
  this.webSocketServer.on('error', (ws, error) => {
216
156
  this.log.error(`WebSocketServer error: ${error}`);
217
157
  });
218
- // Endpoint to validate login code
219
158
  this.expressApp.post('/api/login', express.json(), async (req, res) => {
220
159
  const { password } = req.body;
221
160
  this.log.debug('The frontend sent /api/login', password);
@@ -234,60 +173,74 @@ export class Frontend {
234
173
  this.log.warn('/api/login error wrong password');
235
174
  res.json({ valid: false });
236
175
  }
237
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
238
176
  }
239
177
  catch (error) {
240
178
  this.log.error('/api/login error getting password');
241
179
  res.json({ valid: false });
242
180
  }
243
181
  });
244
- // Endpoint to provide health check
245
182
  this.expressApp.get('/health', (req, res) => {
246
183
  this.log.debug('Express received /health');
247
184
  const healthStatus = {
248
- status: 'ok', // Indicate service is healthy
249
- uptime: process.uptime(), // Server uptime in seconds
250
- timestamp: new Date().toISOString(), // Current timestamp
185
+ status: 'ok',
186
+ uptime: process.uptime(),
187
+ timestamp: new Date().toISOString(),
251
188
  };
252
189
  res.status(200).json(healthStatus);
253
190
  });
254
- // Endpoint to provide settings
191
+ this.expressApp.get('/memory', async (req, res) => {
192
+ this.log.debug('Express received /memory');
193
+ const formatMemoryUsage = (bytes) => {
194
+ const kb = bytes / 1024;
195
+ const mb = kb / 1024;
196
+ return mb >= 1 ? `${mb.toFixed(2)} MB` : `${kb.toFixed(2)} KB`;
197
+ };
198
+ const memoryUsageRaw = process.memoryUsage();
199
+ const memoryUsage = {
200
+ rss: formatMemoryUsage(memoryUsageRaw.rss),
201
+ heapTotal: formatMemoryUsage(memoryUsageRaw.heapTotal),
202
+ heapUsed: formatMemoryUsage(memoryUsageRaw.heapUsed),
203
+ external: formatMemoryUsage(memoryUsageRaw.external),
204
+ arrayBuffers: formatMemoryUsage(memoryUsageRaw.arrayBuffers),
205
+ };
206
+ const { default: v8 } = await import('node:v8');
207
+ const heapStatsRaw = v8.getHeapStatistics();
208
+ const heapSpacesRaw = v8.getHeapSpaceStatistics();
209
+ const heapStats = Object.fromEntries(Object.entries(heapStatsRaw).map(([key, value]) => [key, formatMemoryUsage(value)]));
210
+ const heapSpaces = heapSpacesRaw.map((space) => ({
211
+ ...space,
212
+ space_size: formatMemoryUsage(space.space_size),
213
+ space_used_size: formatMemoryUsage(space.space_used_size),
214
+ space_available_size: formatMemoryUsage(space.space_available_size),
215
+ physical_space_size: formatMemoryUsage(space.physical_space_size),
216
+ }));
217
+ const { default: module } = await import('module');
218
+ const loadedModules = module._cache ? Object.keys(module._cache).sort() : [];
219
+ const memoryReport = {
220
+ memoryUsage,
221
+ heapStats,
222
+ heapSpaces,
223
+ loadedModules,
224
+ };
225
+ res.status(200).json(memoryReport);
226
+ });
227
+ this.expressApp.get('/api/advertise', express.json(), async (req, res) => {
228
+ const pairingCodes = await this.matterbridge.advertiseServerNode(this.matterbridge.serverNode);
229
+ res.json(pairingCodes);
230
+ });
255
231
  this.expressApp.get('/api/settings', express.json(), async (req, res) => {
256
232
  this.log.debug('The frontend sent /api/settings');
257
- this.matterbridge.matterbridgeInformation.bridgeMode = this.matterbridge.bridgeMode;
258
- this.matterbridge.matterbridgeInformation.restartMode = this.matterbridge.restartMode;
259
- this.matterbridge.matterbridgeInformation.loggerLevel = this.log.logLevel;
260
- this.matterbridge.matterbridgeInformation.matterLoggerLevel = Logger.defaultLogLevel;
261
- this.matterbridge.matterbridgeInformation.mattermdnsinterface = (await this.matterbridge.nodeContext?.get('mattermdnsinterface', '')) || '';
262
- this.matterbridge.matterbridgeInformation.matteripv4address = (await this.matterbridge.nodeContext?.get('matteripv4address', '')) || '';
263
- this.matterbridge.matterbridgeInformation.matteripv6address = (await this.matterbridge.nodeContext?.get('matteripv6address', '')) || '';
264
- this.matterbridge.matterbridgeInformation.matterPort = (await this.matterbridge.nodeContext?.get('matterport', 5540)) ?? 5540;
265
- this.matterbridge.matterbridgeInformation.matterDiscriminator = await this.matterbridge.nodeContext?.get('matterdiscriminator');
266
- this.matterbridge.matterbridgeInformation.matterPasscode = await this.matterbridge.nodeContext?.get('matterpasscode');
267
- this.matterbridge.matterbridgeInformation.matterbridgePaired = this.matterbridge.matterbridgePaired;
268
- this.matterbridge.matterbridgeInformation.matterbridgeConnected = this.matterbridge.matterbridgeConnected;
269
- this.matterbridge.matterbridgeInformation.matterbridgeQrPairingCode = this.matterbridge.matterbridgeQrPairingCode;
270
- this.matterbridge.matterbridgeInformation.matterbridgeManualPairingCode = this.matterbridge.matterbridgeManualPairingCode;
271
- this.matterbridge.matterbridgeInformation.matterbridgeFabricInformations = this.matterbridge.matterbridgeFabricInformations;
272
- this.matterbridge.matterbridgeInformation.matterbridgeSessionInformations = Array.from(this.matterbridge.matterbridgeSessionInformations.values());
273
- this.matterbridge.matterbridgeInformation.profile = this.matterbridge.profile;
274
- const response = { systemInformation: this.matterbridge.systemInformation, matterbridgeInformation: this.matterbridge.matterbridgeInformation };
275
- // this.log.debug('Response:', debugStringify(response));
276
- res.json(response);
233
+ res.json(await this.getApiSettings());
277
234
  });
278
- // Endpoint to provide plugins
279
235
  this.expressApp.get('/api/plugins', async (req, res) => {
280
236
  this.log.debug('The frontend sent /api/plugins');
281
- const response = await this.getBaseRegisteredPlugins();
282
- // this.log.debug('Response:', debugStringify(response));
237
+ const response = this.getBaseRegisteredPlugins();
283
238
  res.json(response);
284
239
  });
285
- // Endpoint to provide devices
286
240
  this.expressApp.get('/api/devices', (req, res) => {
287
241
  this.log.debug('The frontend sent /api/devices');
288
242
  const devices = [];
289
243
  this.matterbridge.devices.forEach(async (device) => {
290
- // Check if the device has the required properties
291
244
  if (!device.plugin || !device.name || !device.deviceName || !device.serialNumber || !device.uniqueId)
292
245
  return;
293
246
  const cluster = this.getClusterTextFromDevice(device);
@@ -303,10 +256,8 @@ export class Frontend {
303
256
  cluster: cluster,
304
257
  });
305
258
  });
306
- // this.log.debug('Response:', debugStringify(data));
307
259
  res.json(devices);
308
260
  });
309
- // Endpoint to provide the cluster servers of the devices
310
261
  this.expressApp.get('/api/devices_clusters/:selectedPluginName/:selectedDeviceEndpoint', (req, res) => {
311
262
  const selectedPluginName = req.params.selectedPluginName;
312
263
  const selectedDeviceEndpoint = parseInt(req.params.selectedDeviceEndpoint, 10);
@@ -379,7 +330,6 @@ export class Frontend {
379
330
  });
380
331
  res.json(data);
381
332
  });
382
- // Endpoint to view the log
383
333
  this.expressApp.get('/api/view-log', async (req, res) => {
384
334
  this.log.debug('The frontend sent /api/log');
385
335
  try {
@@ -392,12 +342,10 @@ export class Frontend {
392
342
  res.status(500).send('Error reading log file');
393
343
  }
394
344
  });
395
- // Endpoint to download the matterbridge log
396
345
  this.expressApp.get('/api/download-mblog', async (req, res) => {
397
346
  this.log.debug('The frontend sent /api/download-mblog');
398
347
  try {
399
348
  await fs.access(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterbrideLoggerFile), fs.constants.F_OK);
400
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
401
349
  }
402
350
  catch (error) {
403
351
  fs.appendFile(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterbrideLoggerFile), 'Enable the log on file in the settings to enable the file logger');
@@ -409,12 +357,10 @@ export class Frontend {
409
357
  }
410
358
  });
411
359
  });
412
- // Endpoint to download the matter log
413
360
  this.expressApp.get('/api/download-mjlog', async (req, res) => {
414
361
  this.log.debug('The frontend sent /api/download-mjlog');
415
362
  try {
416
363
  await fs.access(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterLoggerFile), fs.constants.F_OK);
417
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
418
364
  }
419
365
  catch (error) {
420
366
  fs.appendFile(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterLoggerFile), 'Enable the log on file in the settings to enable the file logger');
@@ -426,17 +372,16 @@ export class Frontend {
426
372
  }
427
373
  });
428
374
  });
429
- // Endpoint to download the matter storage file
430
- this.expressApp.get('/api/download-mjstorage', (req, res) => {
375
+ this.expressApp.get('/api/download-mjstorage', async (req, res) => {
431
376
  this.log.debug('The frontend sent /api/download-mjstorage');
432
- res.download(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterStorageName), 'matterbridge.json', (error) => {
377
+ await createZip(path.join(os.tmpdir(), `matterbridge.${this.matterbridge.matterStorageName}.zip`), path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterStorageName));
378
+ res.download(path.join(os.tmpdir(), `matterbridge.${this.matterbridge.matterStorageName}.zip`), `matterbridge.${this.matterbridge.matterStorageName}.zip`, (error) => {
433
379
  if (error) {
434
- this.log.error(`Error downloading log file ${this.matterbridge.matterStorageName}: ${error instanceof Error ? error.message : error}`);
435
- res.status(500).send('Error downloading the matter storage file');
380
+ this.log.error(`Error downloading the matter storage matterbridge.${this.matterbridge.matterStorageName}.zip: ${error instanceof Error ? error.message : error}`);
381
+ res.status(500).send('Error downloading the matter storage zip file');
436
382
  }
437
383
  });
438
384
  });
439
- // Endpoint to download the matterbridge storage directory
440
385
  this.expressApp.get('/api/download-mbstorage', async (req, res) => {
441
386
  this.log.debug('The frontend sent /api/download-mbstorage');
442
387
  await createZip(path.join(os.tmpdir(), `matterbridge.${this.matterbridge.nodeStorageName}.zip`), path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.nodeStorageName));
@@ -447,7 +392,6 @@ export class Frontend {
447
392
  }
448
393
  });
449
394
  });
450
- // Endpoint to download the matterbridge plugin directory
451
395
  this.expressApp.get('/api/download-pluginstorage', async (req, res) => {
452
396
  this.log.debug('The frontend sent /api/download-pluginstorage');
453
397
  await createZip(path.join(os.tmpdir(), `matterbridge.pluginstorage.zip`), this.matterbridge.matterbridgePluginDirectory);
@@ -458,11 +402,9 @@ export class Frontend {
458
402
  }
459
403
  });
460
404
  });
461
- // Endpoint to download the matterbridge plugin config files
462
405
  this.expressApp.get('/api/download-pluginconfig', async (req, res) => {
463
406
  this.log.debug('The frontend sent /api/download-pluginconfig');
464
407
  await createZip(path.join(os.tmpdir(), `matterbridge.pluginconfig.zip`), path.relative(process.cwd(), path.join(this.matterbridge.matterbridgeDirectory, '*.config.json')));
465
- // await createZip(path.join(os.tmpdir(), `matterbridge.pluginconfig.zip`), path.relative(process.cwd(), path.join(this.matterbridge.matterbridgeDirectory, 'certs', '*.*')), path.relative(process.cwd(), path.join(this.matterbridge.matterbridgeDirectory, '*.config.json')));
466
408
  res.download(path.join(os.tmpdir(), `matterbridge.pluginconfig.zip`), `matterbridge.pluginconfig.zip`, (error) => {
467
409
  if (error) {
468
410
  this.log.error(`Error downloading file matterbridge.pluginstorage.zip: ${error instanceof Error ? error.message : error}`);
@@ -470,7 +412,6 @@ export class Frontend {
470
412
  }
471
413
  });
472
414
  });
473
- // Endpoint to download the matterbridge plugin config files
474
415
  this.expressApp.get('/api/download-backup', async (req, res) => {
475
416
  this.log.debug('The frontend sent /api/download-backup');
476
417
  res.download(path.join(os.tmpdir(), `matterbridge.backup.zip`), `matterbridge.backup.zip`, (error) => {
@@ -480,7 +421,6 @@ export class Frontend {
480
421
  }
481
422
  });
482
423
  });
483
- // Endpoint to receive commands
484
424
  this.expressApp.post('/api/command/:command/:param', express.json(), async (req, res) => {
485
425
  const command = req.params.command;
486
426
  let param = req.params.param;
@@ -490,15 +430,13 @@ export class Frontend {
490
430
  return;
491
431
  }
492
432
  this.log.debug(`Received frontend command: ${command}:${param}`);
493
- // Handle the command setpassword from Settings
494
433
  if (command === 'setpassword') {
495
- const password = param.slice(1, -1); // Remove the first and last characters
434
+ const password = param.slice(1, -1);
496
435
  this.log.debug('setpassword', param, password);
497
436
  await this.matterbridge.nodeContext?.set('password', password);
498
437
  res.json({ message: 'Command received' });
499
438
  return;
500
439
  }
501
- // Handle the command setbridgemode from Settings
502
440
  if (command === 'setbridgemode') {
503
441
  this.log.debug(`setbridgemode: ${param}`);
504
442
  this.wssSendRestartRequired();
@@ -506,7 +444,6 @@ export class Frontend {
506
444
  res.json({ message: 'Command received' });
507
445
  return;
508
446
  }
509
- // Handle the command backup from Settings
510
447
  if (command === 'backup') {
511
448
  this.log.notice(`Prepairing the backup...`);
512
449
  await createZip(path.join(os.tmpdir(), `matterbridge.backup.zip`), path.join(this.matterbridge.matterbridgeDirectory), path.join(this.matterbridge.matterbridgePluginDirectory));
@@ -514,26 +451,25 @@ export class Frontend {
514
451
  res.json({ message: 'Command received' });
515
452
  return;
516
453
  }
517
- // Handle the command setmbloglevel from Settings
518
454
  if (command === 'setmbloglevel') {
519
455
  this.log.debug('Matterbridge log level:', param);
520
456
  if (param === 'Debug') {
521
- this.log.logLevel = LogLevel.DEBUG;
457
+ this.log.logLevel = "debug";
522
458
  }
523
459
  else if (param === 'Info') {
524
- this.log.logLevel = LogLevel.INFO;
460
+ this.log.logLevel = "info";
525
461
  }
526
462
  else if (param === 'Notice') {
527
- this.log.logLevel = LogLevel.NOTICE;
463
+ this.log.logLevel = "notice";
528
464
  }
529
465
  else if (param === 'Warn') {
530
- this.log.logLevel = LogLevel.WARN;
466
+ this.log.logLevel = "warn";
531
467
  }
532
468
  else if (param === 'Error') {
533
- this.log.logLevel = LogLevel.ERROR;
469
+ this.log.logLevel = "error";
534
470
  }
535
471
  else if (param === 'Fatal') {
536
- this.log.logLevel = LogLevel.FATAL;
472
+ this.log.logLevel = "fatal";
537
473
  }
538
474
  await this.matterbridge.nodeContext?.set('matterbridgeLogLevel', this.log.logLevel);
539
475
  MatterbridgeEndpoint.logLevel = this.log.logLevel;
@@ -541,13 +477,12 @@ export class Frontend {
541
477
  for (const plugin of this.matterbridge.plugins) {
542
478
  if (!plugin.platform || !plugin.platform.config)
543
479
  continue;
544
- plugin.platform.log.logLevel = plugin.platform.config.debug ? LogLevel.DEBUG : this.log.logLevel;
545
- await plugin.platform.onChangeLoggerLevel(plugin.platform.config.debug ? LogLevel.DEBUG : this.log.logLevel);
480
+ plugin.platform.log.logLevel = plugin.platform.config.debug ? "debug" : this.log.logLevel;
481
+ await plugin.platform.onChangeLoggerLevel(plugin.platform.config.debug ? "debug" : this.log.logLevel);
546
482
  }
547
483
  res.json({ message: 'Command received' });
548
484
  return;
549
485
  }
550
- // Handle the command setmbloglevel from Settings
551
486
  if (command === 'setmjloglevel') {
552
487
  this.log.debug('Matter.js log level:', param);
553
488
  if (param === 'Debug') {
@@ -572,34 +507,30 @@ export class Frontend {
572
507
  res.json({ message: 'Command received' });
573
508
  return;
574
509
  }
575
- // Handle the command setmdnsinterface from Settings
576
510
  if (command === 'setmdnsinterface') {
577
- param = param.slice(1, -1); // Remove the first and last characters *mdns*
511
+ param = param.slice(1, -1);
578
512
  this.matterbridge.matterbridgeInformation.mattermdnsinterface = param;
579
513
  this.log.debug('Matter.js mdns interface:', param === '' ? 'All interfaces' : param);
580
514
  await this.matterbridge.nodeContext?.set('mattermdnsinterface', param);
581
515
  res.json({ message: 'Command received' });
582
516
  return;
583
517
  }
584
- // Handle the command setipv4address from Settings
585
518
  if (command === 'setipv4address') {
586
- param = param.slice(1, -1); // Remove the first and last characters *ip*
519
+ param = param.slice(1, -1);
587
520
  this.matterbridge.matterbridgeInformation.matteripv4address = param;
588
521
  this.log.debug('Matter.js ipv4 address:', param === '' ? 'All ipv4 addresses' : param);
589
522
  await this.matterbridge.nodeContext?.set('matteripv4address', param);
590
523
  res.json({ message: 'Command received' });
591
524
  return;
592
525
  }
593
- // Handle the command setipv6address from Settings
594
526
  if (command === 'setipv6address') {
595
- param = param.slice(1, -1); // Remove the first and last characters *ip*
527
+ param = param.slice(1, -1);
596
528
  this.matterbridge.matterbridgeInformation.matteripv6address = param;
597
529
  this.log.debug('Matter.js ipv6 address:', param === '' ? 'All ipv6 addresses' : param);
598
530
  await this.matterbridge.nodeContext?.set('matteripv6address', param);
599
531
  res.json({ message: 'Command received' });
600
532
  return;
601
533
  }
602
- // Handle the command setmatterport from Settings
603
534
  if (command === 'setmatterport') {
604
535
  const port = Math.min(Math.max(parseInt(param), 5540), 5560);
605
536
  this.matterbridge.matterbridgeInformation.matterPort = port;
@@ -608,7 +539,6 @@ export class Frontend {
608
539
  res.json({ message: 'Command received' });
609
540
  return;
610
541
  }
611
- // Handle the command setmatterdiscriminator from Settings
612
542
  if (command === 'setmatterdiscriminator') {
613
543
  const discriminator = Math.min(Math.max(parseInt(param), 1000), 4095);
614
544
  this.matterbridge.matterbridgeInformation.matterDiscriminator = discriminator;
@@ -617,7 +547,6 @@ export class Frontend {
617
547
  res.json({ message: 'Command received' });
618
548
  return;
619
549
  }
620
- // Handle the command setmatterpasscode from Settings
621
550
  if (command === 'setmatterpasscode') {
622
551
  const passcode = Math.min(Math.max(parseInt(param), 10000000), 90000000);
623
552
  this.matterbridge.matterbridgeInformation.matterPasscode = passcode;
@@ -626,20 +555,17 @@ export class Frontend {
626
555
  res.json({ message: 'Command received' });
627
556
  return;
628
557
  }
629
- // Handle the command setmbloglevel from Settings
630
558
  if (command === 'setmblogfile') {
631
559
  this.log.debug('Matterbridge file log:', param);
632
560
  this.matterbridge.matterbridgeInformation.fileLogger = param === 'true';
633
561
  await this.matterbridge.nodeContext?.set('matterbridgeFileLog', param === 'true');
634
- // Create the file logger for matterbridge
635
562
  if (param === 'true')
636
- AnsiLogger.setGlobalLogfile(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterbrideLoggerFile), LogLevel.DEBUG, true);
563
+ AnsiLogger.setGlobalLogfile(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterbrideLoggerFile), "debug", true);
637
564
  else
638
565
  AnsiLogger.setGlobalLogfile(undefined);
639
566
  res.json({ message: 'Command received' });
640
567
  return;
641
568
  }
642
- // Handle the command setmbloglevel from Settings
643
569
  if (command === 'setmjlogfile') {
644
570
  this.log.debug('Matter file log:', param);
645
571
  this.matterbridge.matterbridgeInformation.matterFileLogger = param === 'true';
@@ -666,43 +592,36 @@ export class Frontend {
666
592
  res.json({ message: 'Command received' });
667
593
  return;
668
594
  }
669
- // Handle the command unregister from Settings
670
595
  if (command === 'unregister') {
671
596
  await this.matterbridge.unregisterAndShutdownProcess();
672
597
  res.json({ message: 'Command received' });
673
598
  return;
674
599
  }
675
- // Handle the command reset from Settings
676
600
  if (command === 'reset') {
677
601
  await this.matterbridge.shutdownProcessAndReset();
678
602
  res.json({ message: 'Command received' });
679
603
  return;
680
604
  }
681
- // Handle the command factoryreset from Settings
682
605
  if (command === 'factoryreset') {
683
606
  await this.matterbridge.shutdownProcessAndFactoryReset();
684
607
  res.json({ message: 'Command received' });
685
608
  return;
686
609
  }
687
- // Handle the command shutdown from Header
688
610
  if (command === 'shutdown') {
689
611
  await this.matterbridge.shutdownProcess();
690
612
  res.json({ message: 'Command received' });
691
613
  return;
692
614
  }
693
- // Handle the command restart from Header
694
615
  if (command === 'restart') {
695
616
  await this.matterbridge.restartProcess();
696
617
  res.json({ message: 'Command received' });
697
618
  return;
698
619
  }
699
- // Handle the command update from Header
700
620
  if (command === 'update') {
701
621
  this.log.info('Updating matterbridge...');
702
622
  try {
703
623
  await this.matterbridge.spawnCommand('npm', ['install', '-g', 'matterbridge', '--omit=dev', '--verbose']);
704
624
  this.log.info('Matterbridge has been updated. Full restart required.');
705
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
706
625
  }
707
626
  catch (error) {
708
627
  this.log.error('Error updating matterbridge');
@@ -712,11 +631,9 @@ export class Frontend {
712
631
  res.json({ message: 'Command received' });
713
632
  return;
714
633
  }
715
- // Handle the command saveconfig from Home
716
634
  if (command === 'saveconfig') {
717
635
  param = param.replace(/\*/g, '\\');
718
636
  this.log.info(`Saving config for plugin ${plg}${param}${nf}...`);
719
- // console.log('Req.body:', JSON.stringify(req.body, null, 2));
720
637
  if (!this.matterbridge.plugins.has(param)) {
721
638
  this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
722
639
  }
@@ -730,58 +647,49 @@ export class Frontend {
730
647
  res.json({ message: 'Command received' });
731
648
  return;
732
649
  }
733
- // Handle the command installplugin from Home
734
650
  if (command === 'installplugin') {
735
651
  param = param.replace(/\*/g, '\\');
736
652
  this.log.info(`Installing plugin ${plg}${param}${nf}...`);
737
653
  try {
738
654
  await this.matterbridge.spawnCommand('npm', ['install', '-g', param, '--omit=dev', '--verbose']);
739
655
  this.log.info(`Plugin ${plg}${param}${nf} installed. Full restart required.`);
740
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
741
656
  }
742
657
  catch (error) {
743
658
  this.log.error(`Error installing plugin ${plg}${param}${er}`);
744
659
  }
745
660
  this.wssSendRestartRequired();
746
661
  param = param.split('@')[0];
747
- // Also add the plugin to matterbridge so no return!
748
662
  if (param === 'matterbridge') {
749
- // If we used the command installplugin to install a dev or a specific version of matterbridge we don't want to add it to matterbridge
750
663
  res.json({ message: 'Command received' });
751
664
  return;
752
665
  }
753
666
  }
754
- // Handle the command addplugin from Home
755
667
  if (command === 'addplugin' || command === 'installplugin') {
756
668
  param = param.replace(/\*/g, '\\');
757
669
  const plugin = await this.matterbridge.plugins.add(param);
758
670
  if (plugin) {
759
671
  if (this.matterbridge.bridgeMode === 'childbridge') {
760
- // We don't know now if the plugin is a dynamic platform or an accessory platform so we create the server node and the aggregator node
761
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
762
672
  this.matterbridge.createDynamicPlugin(plugin, true);
763
673
  }
764
- this.matterbridge.plugins.load(plugin, true, 'The plugin has been added', true); // No await do it in the background
674
+ this.matterbridge.plugins.load(plugin, true, 'The plugin has been added', true);
765
675
  }
766
676
  res.json({ message: 'Command received' });
767
677
  this.wssSendRefreshRequired();
768
678
  return;
769
679
  }
770
- // Handle the command removeplugin from Home
771
680
  if (command === 'removeplugin') {
772
681
  if (!this.matterbridge.plugins.has(param)) {
773
682
  this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
774
683
  }
775
684
  else {
776
685
  const plugin = this.matterbridge.plugins.get(param);
777
- await this.matterbridge.plugins.shutdown(plugin, 'The plugin has been removed.', true); // This will also close the server node in childbridge mode
686
+ await this.matterbridge.plugins.shutdown(plugin, 'The plugin has been removed.', true);
778
687
  await this.matterbridge.plugins.remove(param);
779
688
  }
780
689
  res.json({ message: 'Command received' });
781
690
  this.wssSendRefreshRequired();
782
691
  return;
783
692
  }
784
- // Handle the command enableplugin from Home
785
693
  if (command === 'enableplugin') {
786
694
  if (!this.matterbridge.plugins.has(param)) {
787
695
  this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
@@ -794,23 +702,20 @@ export class Frontend {
794
702
  plugin.loaded = undefined;
795
703
  plugin.started = undefined;
796
704
  plugin.configured = undefined;
797
- plugin.connected = undefined;
798
705
  plugin.platform = undefined;
799
706
  plugin.registeredDevices = undefined;
800
707
  plugin.addedDevices = undefined;
801
708
  await this.matterbridge.plugins.enable(param);
802
709
  if (this.matterbridge.bridgeMode === 'childbridge' && plugin.type === 'DynamicPlatform') {
803
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
804
710
  this.matterbridge.createDynamicPlugin(plugin, true);
805
711
  }
806
- this.matterbridge.plugins.load(plugin, true, 'The plugin has been enabled', true); // No await do it in the background since the server node is already started
712
+ this.matterbridge.plugins.load(plugin, true, 'The plugin has been enabled', true);
807
713
  }
808
714
  }
809
715
  res.json({ message: 'Command received' });
810
716
  this.wssSendRefreshRequired();
811
717
  return;
812
718
  }
813
- // Handle the command disableplugin from Home
814
719
  if (command === 'disableplugin') {
815
720
  if (!this.matterbridge.plugins.has(param)) {
816
721
  this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
@@ -818,7 +723,7 @@ export class Frontend {
818
723
  else {
819
724
  const plugin = this.matterbridge.plugins.get(param);
820
725
  if (plugin && plugin.enabled) {
821
- await this.matterbridge.plugins.shutdown(plugin, 'The plugin has been disabled.', true); // This will also close the server node in childbridge mode
726
+ await this.matterbridge.plugins.shutdown(plugin, 'The plugin has been disabled.', true);
822
727
  await this.matterbridge.plugins.disable(param);
823
728
  }
824
729
  }
@@ -827,7 +732,6 @@ export class Frontend {
827
732
  return;
828
733
  }
829
734
  });
830
- // Fallback for routing (must be the last route)
831
735
  this.expressApp.get('*', (req, res) => {
832
736
  this.log.debug('The frontend sent:', req.url);
833
737
  this.log.debug('Response send file:', path.join(this.matterbridge.rootDirectory, 'frontend/build/index.html'));
@@ -836,29 +740,24 @@ export class Frontend {
836
740
  this.log.debug(`Frontend initialized on port ${YELLOW}${this.port}${db} static ${UNDERLINE}${path.join(this.matterbridge.rootDirectory, 'frontend/build')}${UNDERLINEOFF}${rs}`);
837
741
  }
838
742
  async stop() {
839
- // Close the http server
840
743
  if (this.httpServer) {
841
744
  this.httpServer.close();
842
745
  this.httpServer.removeAllListeners();
843
746
  this.httpServer = undefined;
844
747
  this.log.debug('Frontend http server closed successfully');
845
748
  }
846
- // Close the https server
847
749
  if (this.httpsServer) {
848
750
  this.httpsServer.close();
849
751
  this.httpsServer.removeAllListeners();
850
752
  this.httpsServer = undefined;
851
753
  this.log.debug('Frontend https server closed successfully');
852
754
  }
853
- // Remove listeners from the express app
854
755
  if (this.expressApp) {
855
756
  this.expressApp.removeAllListeners();
856
757
  this.expressApp = undefined;
857
758
  this.log.debug('Frontend app closed successfully');
858
759
  }
859
- // Close the WebSocket server
860
760
  if (this.webSocketServer) {
861
- // Close all active connections
862
761
  this.webSocketServer.clients.forEach((client) => {
863
762
  if (client.readyState === WebSocket.OPEN) {
864
763
  client.close();
@@ -875,11 +774,25 @@ export class Frontend {
875
774
  this.webSocketServer = undefined;
876
775
  }
877
776
  }
878
- /**
879
- * Retrieves the cluster text description from a given device.
880
- * @param {MatterbridgeDevice} device - The MatterbridgeDevice object.
881
- * @returns {string} The attributes description of the cluster servers in the device.
882
- */
777
+ async getApiSettings() {
778
+ this.matterbridge.matterbridgeInformation.bridgeMode = this.matterbridge.bridgeMode;
779
+ this.matterbridge.matterbridgeInformation.restartMode = this.matterbridge.restartMode;
780
+ this.matterbridge.matterbridgeInformation.loggerLevel = this.log.logLevel;
781
+ this.matterbridge.matterbridgeInformation.matterLoggerLevel = Logger.defaultLogLevel;
782
+ this.matterbridge.matterbridgeInformation.mattermdnsinterface = this.matterbridge.mdnsInterface;
783
+ this.matterbridge.matterbridgeInformation.matteripv4address = this.matterbridge.ipv4address;
784
+ this.matterbridge.matterbridgeInformation.matteripv6address = this.matterbridge.ipv6address;
785
+ this.matterbridge.matterbridgeInformation.matterPort = (await this.matterbridge.nodeContext?.get('matterport', 5540)) ?? 5540;
786
+ this.matterbridge.matterbridgeInformation.matterDiscriminator = await this.matterbridge.nodeContext?.get('matterdiscriminator');
787
+ this.matterbridge.matterbridgeInformation.matterPasscode = await this.matterbridge.nodeContext?.get('matterpasscode');
788
+ this.matterbridge.matterbridgeInformation.matterbridgePaired = this.matterbridge.matterbridgePaired;
789
+ this.matterbridge.matterbridgeInformation.matterbridgeQrPairingCode = this.matterbridge.matterbridgeQrPairingCode;
790
+ this.matterbridge.matterbridgeInformation.matterbridgeManualPairingCode = this.matterbridge.matterbridgeManualPairingCode;
791
+ this.matterbridge.matterbridgeInformation.matterbridgeFabricInformations = this.matterbridge.matterbridgeFabricInformations;
792
+ this.matterbridge.matterbridgeInformation.matterbridgeSessionInformations = this.matterbridge.matterbridgeSessionInformations;
793
+ this.matterbridge.matterbridgeInformation.profile = this.matterbridge.profile;
794
+ return { systemInformation: this.matterbridge.systemInformation, matterbridgeInformation: this.matterbridge.matterbridgeInformation };
795
+ }
883
796
  getClusterTextFromDevice(device) {
884
797
  const getAttribute = (device, cluster, attribute) => {
885
798
  let value = undefined;
@@ -917,10 +830,10 @@ export class Frontend {
917
830
  return '';
918
831
  };
919
832
  let attributes = '';
920
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
921
833
  Object.entries(device.state).forEach(([clusterName, clusterAttributes]) => {
922
834
  Object.entries(clusterAttributes).forEach(([attributeName, attributeValue]) => {
923
- // console.log(`Cluster: ${clusterName} Attribute: ${attributeName} Value: ${attributeValue}`);
835
+ if (typeof attributeValue === 'undefined')
836
+ return;
924
837
  if (clusterName === 'onOff' && attributeName === 'onOff')
925
838
  attributes += `OnOff: ${attributeValue} `;
926
839
  if (clusterName === 'switch' && attributeName === 'currentPosition')
@@ -991,11 +904,7 @@ export class Frontend {
991
904
  });
992
905
  return attributes.trimStart().trimEnd();
993
906
  }
994
- /**
995
- * Retrieves the base registered plugins sanitized for res.json().
996
- * @returns {BaseRegisteredPlugin[]} A promise that resolves to an array of BaseRegisteredPlugin objects.
997
- */
998
- async getBaseRegisteredPlugins() {
907
+ getBaseRegisteredPlugins() {
999
908
  const baseRegisteredPlugins = [];
1000
909
  for (const plugin of this.matterbridge.plugins) {
1001
910
  baseRegisteredPlugins.push({
@@ -1013,7 +922,6 @@ export class Frontend {
1013
922
  started: plugin.started,
1014
923
  configured: plugin.configured,
1015
924
  paired: plugin.paired,
1016
- connected: plugin.connected,
1017
925
  fabricInformations: plugin.fabricInformations,
1018
926
  sessionInformations: plugin.sessionInformations,
1019
927
  registeredDevices: plugin.registeredDevices,
@@ -1026,14 +934,6 @@ export class Frontend {
1026
934
  }
1027
935
  return baseRegisteredPlugins;
1028
936
  }
1029
- /**
1030
- * Handles incoming websocket messages for the Matterbridge.
1031
- *
1032
- * @param {Matterbridge} this - The Matterbridge instance.
1033
- * @param {WebSocket} client - The websocket client that sent the message.
1034
- * @param {WebSocket.RawData} message - The raw data of the message received from the client.
1035
- * @returns {Promise<void>} A promise that resolves when the message has been handled.
1036
- */
1037
937
  async wsMessageHandler(client, message) {
1038
938
  let data;
1039
939
  try {
@@ -1104,40 +1004,25 @@ export class Frontend {
1104
1004
  await this.matterbridge.shutdownProcess();
1105
1005
  return;
1106
1006
  }
1007
+ else if (data.method === '/api/advertise') {
1008
+ const pairingCodes = await this.matterbridge.advertiseServerNode(this.matterbridge.serverNode);
1009
+ client.send(JSON.stringify({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, response: pairingCodes }));
1010
+ return;
1011
+ }
1107
1012
  else if (data.method === '/api/settings') {
1108
- this.matterbridge.matterbridgeInformation.bridgeMode = this.matterbridge.bridgeMode;
1109
- this.matterbridge.matterbridgeInformation.restartMode = this.matterbridge.restartMode;
1110
- this.matterbridge.matterbridgeInformation.loggerLevel = this.log.logLevel;
1111
- this.matterbridge.matterbridgeInformation.matterLoggerLevel = Logger.defaultLogLevel;
1112
- this.matterbridge.matterbridgeInformation.mattermdnsinterface = (await this.matterbridge.nodeContext?.get('mattermdnsinterface', '')) || '';
1113
- this.matterbridge.matterbridgeInformation.matteripv4address = (await this.matterbridge.nodeContext?.get('matteripv4address', '')) || '';
1114
- this.matterbridge.matterbridgeInformation.matteripv6address = (await this.matterbridge.nodeContext?.get('matteripv6address', '')) || '';
1115
- this.matterbridge.matterbridgeInformation.matterPort = (await this.matterbridge.nodeContext?.get('matterport', 5540)) ?? 5540;
1116
- this.matterbridge.matterbridgeInformation.matterDiscriminator = await this.matterbridge.nodeContext?.get('matterdiscriminator');
1117
- this.matterbridge.matterbridgeInformation.matterPasscode = await this.matterbridge.nodeContext?.get('matterpasscode');
1118
- this.matterbridge.matterbridgeInformation.matterbridgePaired = this.matterbridge.matterbridgePaired;
1119
- this.matterbridge.matterbridgeInformation.matterbridgeConnected = this.matterbridge.matterbridgeConnected;
1120
- this.matterbridge.matterbridgeInformation.matterbridgeQrPairingCode = this.matterbridge.matterbridgeQrPairingCode;
1121
- this.matterbridge.matterbridgeInformation.matterbridgeManualPairingCode = this.matterbridge.matterbridgeManualPairingCode;
1122
- this.matterbridge.matterbridgeInformation.matterbridgeFabricInformations = this.matterbridge.matterbridgeFabricInformations;
1123
- this.matterbridge.matterbridgeInformation.matterbridgeSessionInformations = Array.from(this.matterbridge.matterbridgeSessionInformations.values());
1124
- this.matterbridge.matterbridgeInformation.profile = this.matterbridge.profile;
1125
- const response = { systemInformation: this.matterbridge.systemInformation, matterbridgeInformation: this.matterbridge.matterbridgeInformation };
1126
- client.send(JSON.stringify({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, response }));
1013
+ client.send(JSON.stringify({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, response: await this.getApiSettings() }));
1127
1014
  return;
1128
1015
  }
1129
1016
  else if (data.method === '/api/plugins') {
1130
- const response = await this.getBaseRegisteredPlugins();
1017
+ const response = this.getBaseRegisteredPlugins();
1131
1018
  client.send(JSON.stringify({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, response }));
1132
1019
  return;
1133
1020
  }
1134
1021
  else if (data.method === '/api/devices') {
1135
1022
  const devices = [];
1136
1023
  this.matterbridge.devices.forEach(async (device) => {
1137
- // Filter by pluginName if provided
1138
1024
  if (data.params.pluginName && data.params.pluginName !== device.plugin)
1139
1025
  return;
1140
- // Check if the device has the required properties
1141
1026
  if (!device.plugin || !device.name || !device.deviceName || !device.serialNumber || !device.uniqueId)
1142
1027
  return;
1143
1028
  const cluster = this.getClusterTextFromDevice(device);
@@ -1217,7 +1102,6 @@ export class Frontend {
1217
1102
  });
1218
1103
  endpointServer.getChildEndpoints().forEach((childEndpoint) => {
1219
1104
  deviceTypes = [];
1220
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1221
1105
  const name = childEndpoint.endpoint?.id;
1222
1106
  const clusterServers = childEndpoint.getAllClusterServers();
1223
1107
  clusterServers.forEach((clusterServer) => {
@@ -1300,73 +1184,44 @@ export class Frontend {
1300
1184
  return;
1301
1185
  }
1302
1186
  }
1303
- /**
1304
- * Sends a WebSocket message to all connected clients.
1305
- *
1306
- * @param {string} level - The logger level of the message: debug info notice warn error fatal...
1307
- * @param {string} time - The time string of the message
1308
- * @param {string} name - The logger name of the message
1309
- * @param {string} message - The content of the message.
1310
- */
1311
1187
  wssSendMessage(level, time, name, message) {
1312
1188
  if (!level || !time || !name || !message)
1313
1189
  return;
1314
- // Remove ANSI escape codes from the message
1315
- // eslint-disable-next-line no-control-regex
1316
1190
  message = message.replace(/\x1B\[[0-9;]*[m|s|u|K]/g, '');
1317
- // Remove leading asterisks from the message
1318
1191
  message = message.replace(/^\*+/, '');
1319
- // Replace all occurrences of \t and \n
1320
1192
  message = message.replace(/[\t\n]/g, '');
1321
- // Remove non-printable characters
1322
- // eslint-disable-next-line no-control-regex
1323
1193
  message = message.replace(/[\x00-\x1F\x7F]/g, '');
1324
- // Replace all occurrences of \" with "
1325
1194
  message = message.replace(/\\"/g, '"');
1326
- // Define the maximum allowed length for continuous characters without a space
1327
1195
  const maxContinuousLength = 100;
1328
1196
  const keepStartLength = 20;
1329
1197
  const keepEndLength = 20;
1330
- // Split the message into words
1331
1198
  message = message
1332
1199
  .split(' ')
1333
1200
  .map((word) => {
1334
- // If the word length exceeds the max continuous length, insert spaces and truncate
1335
1201
  if (word.length > maxContinuousLength) {
1336
1202
  return word.slice(0, keepStartLength) + ' ... ' + word.slice(-keepEndLength);
1337
1203
  }
1338
1204
  return word;
1339
1205
  })
1340
1206
  .join(' ');
1341
- // Send the message to all connected clients
1342
1207
  this.webSocketServer?.clients.forEach((client) => {
1343
1208
  if (client.readyState === WebSocket.OPEN) {
1344
1209
  client.send(JSON.stringify({ id: WS_ID_LOG, src: 'Matterbridge', level, time, name, message }));
1345
1210
  }
1346
1211
  });
1347
1212
  }
1348
- /**
1349
- * Sends a need to refresh WebSocket message to all connected clients.
1350
- *
1351
- */
1352
1213
  wssSendRefreshRequired() {
1353
1214
  this.log.debug('Sending a refresh required message to all connected clients');
1354
1215
  this.matterbridge.matterbridgeInformation.refreshRequired = true;
1355
- // Send the message to all connected clients
1356
1216
  this.webSocketServer?.clients.forEach((client) => {
1357
1217
  if (client.readyState === WebSocket.OPEN) {
1358
1218
  client.send(JSON.stringify({ id: WS_ID_REFRESH_NEEDED, src: 'Matterbridge', dst: 'Frontend', method: 'refresh_required', params: {} }));
1359
1219
  }
1360
1220
  });
1361
1221
  }
1362
- /**
1363
- * Sends a need to restart WebSocket message to all connected clients.
1364
- *
1365
- */
1366
1222
  wssSendRestartRequired() {
1367
1223
  this.log.debug('Sending a restart required message to all connected clients');
1368
1224
  this.matterbridge.matterbridgeInformation.restartRequired = true;
1369
- // Send the message to all connected clients
1370
1225
  this.webSocketServer?.clients.forEach((client) => {
1371
1226
  if (client.readyState === WebSocket.OPEN) {
1372
1227
  client.send(JSON.stringify({ id: WS_ID_RESTART_NEEDED, src: 'Matterbridge', dst: 'Frontend', method: 'restart_required', params: {} }));
@@ -1374,4 +1229,3 @@ export class Frontend {
1374
1229
  });
1375
1230
  }
1376
1231
  }
1377
- //# sourceMappingURL=frontend.js.map