matterbridge 2.1.1 → 2.1.2-dev.3

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 (111) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/cli.js +0 -26
  3. package/dist/cluster/export.js +0 -2
  4. package/dist/defaultConfigSchema.js +0 -23
  5. package/dist/deviceManager.js +3 -29
  6. package/dist/frontend.js +51 -245
  7. package/dist/index.js +0 -28
  8. package/dist/logger/export.js +0 -1
  9. package/dist/matter/behaviors.js +0 -2
  10. package/dist/matter/clusters.js +0 -2
  11. package/dist/matter/devices.js +0 -2
  12. package/dist/matter/endpoints.js +0 -2
  13. package/dist/matter/export.js +1 -2
  14. package/dist/matter/types.js +0 -2
  15. package/dist/matterbridge.js +38 -752
  16. package/dist/matterbridgeAccessoryPlatform.js +0 -33
  17. package/dist/matterbridgeBehaviors.js +1 -32
  18. package/dist/matterbridgeDeviceTypes.js +11 -112
  19. package/dist/matterbridgeDynamicPlatform.js +0 -33
  20. package/dist/matterbridgeEndpoint.js +6 -690
  21. package/dist/matterbridgeEndpointHelpers.js +0 -96
  22. package/dist/matterbridgePlatform.js +9 -129
  23. package/dist/matterbridgeTypes.js +0 -24
  24. package/dist/pluginManager.js +5 -243
  25. package/dist/storage/export.js +0 -1
  26. package/dist/utils/colorUtils.js +2 -205
  27. package/dist/utils/export.js +0 -1
  28. package/dist/utils/utils.js +7 -251
  29. package/npm-shrinkwrap.json +2 -2
  30. package/package.json +1 -2
  31. package/dist/cli.d.ts +0 -25
  32. package/dist/cli.d.ts.map +0 -1
  33. package/dist/cli.js.map +0 -1
  34. package/dist/cluster/export.d.ts +0 -2
  35. package/dist/cluster/export.d.ts.map +0 -1
  36. package/dist/cluster/export.js.map +0 -1
  37. package/dist/defaultConfigSchema.d.ts +0 -27
  38. package/dist/defaultConfigSchema.d.ts.map +0 -1
  39. package/dist/defaultConfigSchema.js.map +0 -1
  40. package/dist/deviceManager.d.ts +0 -46
  41. package/dist/deviceManager.d.ts.map +0 -1
  42. package/dist/deviceManager.js.map +0 -1
  43. package/dist/frontend.d.ts +0 -109
  44. package/dist/frontend.d.ts.map +0 -1
  45. package/dist/frontend.js.map +0 -1
  46. package/dist/index.d.ts +0 -35
  47. package/dist/index.d.ts.map +0 -1
  48. package/dist/index.js.map +0 -1
  49. package/dist/logger/export.d.ts +0 -2
  50. package/dist/logger/export.d.ts.map +0 -1
  51. package/dist/logger/export.js.map +0 -1
  52. package/dist/matter/behaviors.d.ts +0 -2
  53. package/dist/matter/behaviors.d.ts.map +0 -1
  54. package/dist/matter/behaviors.js.map +0 -1
  55. package/dist/matter/clusters.d.ts +0 -2
  56. package/dist/matter/clusters.d.ts.map +0 -1
  57. package/dist/matter/clusters.js.map +0 -1
  58. package/dist/matter/devices.d.ts +0 -2
  59. package/dist/matter/devices.d.ts.map +0 -1
  60. package/dist/matter/devices.js.map +0 -1
  61. package/dist/matter/endpoints.d.ts +0 -2
  62. package/dist/matter/endpoints.d.ts.map +0 -1
  63. package/dist/matter/endpoints.js.map +0 -1
  64. package/dist/matter/export.d.ts +0 -4
  65. package/dist/matter/export.d.ts.map +0 -1
  66. package/dist/matter/export.js.map +0 -1
  67. package/dist/matter/types.d.ts +0 -3
  68. package/dist/matter/types.d.ts.map +0 -1
  69. package/dist/matter/types.js.map +0 -1
  70. package/dist/matterbridge.d.ts +0 -409
  71. package/dist/matterbridge.d.ts.map +0 -1
  72. package/dist/matterbridge.js.map +0 -1
  73. package/dist/matterbridgeAccessoryPlatform.d.ts +0 -39
  74. package/dist/matterbridgeAccessoryPlatform.d.ts.map +0 -1
  75. package/dist/matterbridgeAccessoryPlatform.js.map +0 -1
  76. package/dist/matterbridgeBehaviors.d.ts +0 -1056
  77. package/dist/matterbridgeBehaviors.d.ts.map +0 -1
  78. package/dist/matterbridgeBehaviors.js.map +0 -1
  79. package/dist/matterbridgeDeviceTypes.d.ts +0 -177
  80. package/dist/matterbridgeDeviceTypes.d.ts.map +0 -1
  81. package/dist/matterbridgeDeviceTypes.js.map +0 -1
  82. package/dist/matterbridgeDynamicPlatform.d.ts +0 -39
  83. package/dist/matterbridgeDynamicPlatform.d.ts.map +0 -1
  84. package/dist/matterbridgeDynamicPlatform.js.map +0 -1
  85. package/dist/matterbridgeEndpoint.d.ts +0 -834
  86. package/dist/matterbridgeEndpoint.d.ts.map +0 -1
  87. package/dist/matterbridgeEndpoint.js.map +0 -1
  88. package/dist/matterbridgeEndpointHelpers.d.ts +0 -2262
  89. package/dist/matterbridgeEndpointHelpers.d.ts.map +0 -1
  90. package/dist/matterbridgeEndpointHelpers.js.map +0 -1
  91. package/dist/matterbridgePlatform.d.ts +0 -164
  92. package/dist/matterbridgePlatform.d.ts.map +0 -1
  93. package/dist/matterbridgePlatform.js.map +0 -1
  94. package/dist/matterbridgeTypes.d.ts +0 -165
  95. package/dist/matterbridgeTypes.d.ts.map +0 -1
  96. package/dist/matterbridgeTypes.js.map +0 -1
  97. package/dist/pluginManager.d.ts +0 -238
  98. package/dist/pluginManager.d.ts.map +0 -1
  99. package/dist/pluginManager.js.map +0 -1
  100. package/dist/storage/export.d.ts +0 -2
  101. package/dist/storage/export.d.ts.map +0 -1
  102. package/dist/storage/export.js.map +0 -1
  103. package/dist/utils/colorUtils.d.ts +0 -61
  104. package/dist/utils/colorUtils.d.ts.map +0 -1
  105. package/dist/utils/colorUtils.js.map +0 -1
  106. package/dist/utils/export.d.ts +0 -3
  107. package/dist/utils/export.d.ts.map +0 -1
  108. package/dist/utils/export.js.map +0 -1
  109. package/dist/utils/utils.d.ts +0 -221
  110. package/dist/utils/utils.d.ts.map +0 -1
  111. package/dist/utils/utils.js.map +0 -1
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.1
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
9
  import { AnsiLogger, CYAN, db, debugStringify, er, nf, rs, stringify, UNDERLINE, UNDERLINEOFF, wr, YELLOW } from './logger/export.js';
35
- // Matterbridge
36
10
  import { createZip, getIntParameter, 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;
@@ -65,12 +22,13 @@ export class Frontend {
65
22
  httpServer;
66
23
  httpsServer;
67
24
  webSocketServer;
25
+ prevCpus = os.cpus();
68
26
  memoryData = [];
69
27
  memoryInterval;
70
28
  memoryTimeout;
71
29
  constructor(matterbridge) {
72
30
  this.matterbridge = matterbridge;
73
- this.log = new AnsiLogger({ logName: 'Frontend', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: hasParameter('debug') ? "debug" /* LogLevel.DEBUG */ : "info" /* LogLevel.INFO */ });
31
+ this.log = new AnsiLogger({ logName: 'Frontend', logTimestampFormat: 4, logLevel: hasParameter('debug') ? "debug" : "info" });
74
32
  }
75
33
  set logLevel(logLevel) {
76
34
  this.log.logLevel = logLevel;
@@ -78,21 +36,10 @@ export class Frontend {
78
36
  async start(port = 8283) {
79
37
  this.port = port;
80
38
  this.log.debug(`Initializing the frontend ${hasParameter('ssl') ? 'https' : 'http'} server on port ${YELLOW}${this.port}${db}`);
81
- // Create the express app that serves the frontend
82
39
  this.expressApp = express();
83
- // Log all requests to the server for debugging
84
- /*
85
- this.expressApp.use((req, res, next) => {
86
- this.log.debug(`Received request on expressApp: ${req.method} ${req.url}`);
87
- next();
88
- });
89
- */
90
- // Serve static files from '/static' endpoint
91
40
  this.expressApp.use(express.static(path.join(this.matterbridge.rootDirectory, 'frontend/build')));
92
41
  if (!hasParameter('ssl')) {
93
- // Create an HTTP server and attach the express app
94
42
  this.httpServer = createServer(this.expressApp);
95
- // Listen on the specified port
96
43
  if (hasParameter('ingress')) {
97
44
  this.httpServer.listen(this.port, '0.0.0.0', () => {
98
45
  this.log.info(`The frontend http server is listening on ${UNDERLINE}http://0.0.0.0:${this.port}${UNDERLINEOFF}${rs}`);
@@ -106,7 +53,6 @@ export class Frontend {
106
53
  this.log.info(`The frontend http server is listening on ${UNDERLINE}http://[${this.matterbridge.systemInformation.ipv6Address}]:${this.port}${UNDERLINEOFF}${rs}`);
107
54
  });
108
55
  }
109
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
110
56
  this.httpServer.on('error', (error) => {
111
57
  this.log.error(`Frontend http server error listening on ${this.port}`);
112
58
  switch (error.code) {
@@ -122,7 +68,6 @@ export class Frontend {
122
68
  });
123
69
  }
124
70
  else {
125
- // Load the SSL certificate, the private key and optionally the CA certificate
126
71
  let cert;
127
72
  try {
128
73
  cert = await fs.readFile(path.join(this.matterbridge.matterbridgeDirectory, 'certs/cert.pem'), 'utf8');
@@ -150,9 +95,7 @@ export class Frontend {
150
95
  this.log.info(`CA certificate file ${path.join(this.matterbridge.matterbridgeDirectory, 'certs/ca.pem')} not loaded: ${error}`);
151
96
  }
152
97
  const serverOptions = { cert, key, ca };
153
- // Create an HTTPS server with the SSL certificate and private key (ca is optional) and attach the express app
154
98
  this.httpsServer = https.createServer(serverOptions, this.expressApp);
155
- // Listen on the specified port
156
99
  if (hasParameter('ingress')) {
157
100
  this.httpsServer.listen(this.port, '0.0.0.0', () => {
158
101
  this.log.info(`The frontend https server is listening on ${UNDERLINE}https://0.0.0.0:${this.port}${UNDERLINEOFF}${rs}`);
@@ -166,7 +109,6 @@ export class Frontend {
166
109
  this.log.info(`The frontend https server is listening on ${UNDERLINE}https://[${this.matterbridge.systemInformation.ipv6Address}]:${this.port}${UNDERLINEOFF}${rs}`);
167
110
  });
168
111
  }
169
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
170
112
  this.httpsServer.on('error', (error) => {
171
113
  this.log.error(`Frontend https server error listening on ${this.port}`);
172
114
  switch (error.code) {
@@ -183,13 +125,12 @@ export class Frontend {
183
125
  }
184
126
  if (this.initializeError)
185
127
  return;
186
- // Createe a WebSocket server and attach it to the http or https server
187
128
  const wssPort = this.port;
188
129
  const wssHost = hasParameter('ssl') ? `wss://${this.matterbridge.systemInformation.ipv4Address}:${wssPort}` : `ws://${this.matterbridge.systemInformation.ipv4Address}:${wssPort}`;
189
130
  this.webSocketServer = new WebSocketServer(hasParameter('ssl') ? { server: this.httpsServer } : { server: this.httpServer });
190
131
  this.webSocketServer.on('connection', (ws, request) => {
191
132
  const clientIp = request.socket.remoteAddress;
192
- AnsiLogger.setGlobalCallback(this.wssSendMessage.bind(this), "debug" /* LogLevel.DEBUG */);
133
+ AnsiLogger.setGlobalCallback(this.wssSendMessage.bind(this), "debug");
193
134
  this.log.info(`WebSocketServer client "${clientIp}" connected to Matterbridge`);
194
135
  ws.on('message', (message) => {
195
136
  this.wsMessageHandler(ws, message);
@@ -221,11 +162,9 @@ export class Frontend {
221
162
  this.webSocketServer.on('error', (ws, error) => {
222
163
  this.log.error(`WebSocketServer error: ${error}`);
223
164
  });
224
- // Start the memory dump interval
225
165
  if (hasParameter('memorydump')) {
226
- this.startMemoryDump();
166
+ this.startCpuMemoryDump();
227
167
  }
228
- // Endpoint to validate login code
229
168
  this.expressApp.post('/api/login', express.json(), async (req, res) => {
230
169
  const { password } = req.body;
231
170
  this.log.debug('The frontend sent /api/login', password);
@@ -244,27 +183,23 @@ export class Frontend {
244
183
  this.log.warn('/api/login error wrong password');
245
184
  res.json({ valid: false });
246
185
  }
247
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
248
186
  }
249
187
  catch (error) {
250
188
  this.log.error('/api/login error getting password');
251
189
  res.json({ valid: false });
252
190
  }
253
191
  });
254
- // Endpoint to provide health check
255
192
  this.expressApp.get('/health', (req, res) => {
256
193
  this.log.debug('Express received /health');
257
194
  const healthStatus = {
258
- status: 'ok', // Indicate service is healthy
259
- uptime: process.uptime(), // Server uptime in seconds
260
- timestamp: new Date().toISOString(), // Current timestamp
195
+ status: 'ok',
196
+ uptime: process.uptime(),
197
+ timestamp: new Date().toISOString(),
261
198
  };
262
199
  res.status(200).json(healthStatus);
263
200
  });
264
- // Endpoint to provide memory usage details
265
201
  this.expressApp.get('/memory', async (req, res) => {
266
202
  this.log.debug('Express received /memory');
267
- // Memory usage from process
268
203
  const memoryUsageRaw = process.memoryUsage();
269
204
  const memoryUsage = {
270
205
  rss: this.formatMemoryUsage(memoryUsageRaw.rss),
@@ -273,13 +208,10 @@ export class Frontend {
273
208
  external: this.formatMemoryUsage(memoryUsageRaw.external),
274
209
  arrayBuffers: this.formatMemoryUsage(memoryUsageRaw.arrayBuffers),
275
210
  };
276
- // V8 heap statistics
277
211
  const { default: v8 } = await import('node:v8');
278
212
  const heapStatsRaw = v8.getHeapStatistics();
279
213
  const heapSpacesRaw = v8.getHeapSpaceStatistics();
280
- // Format heapStats
281
214
  const heapStats = Object.fromEntries(Object.entries(heapStatsRaw).map(([key, value]) => [key, this.formatMemoryUsage(value)]));
282
- // Format heapSpaces
283
215
  const heapSpaces = heapSpacesRaw.map((space) => ({
284
216
  ...space,
285
217
  space_size: this.formatMemoryUsage(space.space_size),
@@ -289,23 +221,6 @@ export class Frontend {
289
221
  }));
290
222
  const { default: module } = await import('module');
291
223
  const loadedModules = module._cache ? Object.keys(module._cache).sort() : [];
292
- /*
293
- if (req.query.heapdump === 'true') {
294
- const { default: heapdump } = await import('heapdump');
295
- const filename = `heapdump-${Date.now()}.heapsnapshot`;
296
-
297
- heapdump.writeSnapshot(filename, (err, dumpFilename) => {
298
- if (err) {
299
- this.log.error(`Heap dump error: ${err.message}`);
300
- return res.status(500).json({ error: 'Heap dump failed', details: err.message });
301
- }
302
-
303
- this.log.info(`Heap dump written to ${dumpFilename}`);
304
- return res.status(200).json({ ...memoryReport, heapdump: dumpFilename });
305
- });
306
- return; // Exit early since heapdump response is handled inside callback
307
- }
308
- */
309
224
  const memoryReport = {
310
225
  memoryUsage,
311
226
  heapStats,
@@ -314,7 +229,6 @@ export class Frontend {
314
229
  };
315
230
  res.status(200).json(memoryReport);
316
231
  });
317
- // Endpoint to start advertising the server node
318
232
  this.expressApp.get('/api/advertise', express.json(), async (req, res) => {
319
233
  const pairingCodes = await this.matterbridge.advertiseServerNode(this.matterbridge.serverNode);
320
234
  if (pairingCodes) {
@@ -325,24 +239,19 @@ export class Frontend {
325
239
  res.status(500).json({ error: 'Failed to generate pairing codes' });
326
240
  }
327
241
  });
328
- // Endpoint to provide settings
329
242
  this.expressApp.get('/api/settings', express.json(), async (req, res) => {
330
243
  this.log.debug('The frontend sent /api/settings');
331
244
  res.json(await this.getApiSettings());
332
245
  });
333
- // Endpoint to provide plugins
334
246
  this.expressApp.get('/api/plugins', async (req, res) => {
335
247
  this.log.debug('The frontend sent /api/plugins');
336
248
  const response = this.getBaseRegisteredPlugins();
337
- // this.log.debug('Response:', debugStringify(response));
338
249
  res.json(response);
339
250
  });
340
- // Endpoint to provide devices
341
251
  this.expressApp.get('/api/devices', (req, res) => {
342
252
  this.log.debug('The frontend sent /api/devices');
343
253
  const devices = [];
344
254
  this.matterbridge.devices.forEach(async (device) => {
345
- // Check if the device has the required properties
346
255
  if (!device.plugin || !device.name || !device.deviceName || !device.serialNumber || !device.uniqueId)
347
256
  return;
348
257
  const cluster = this.getClusterTextFromDevice(device);
@@ -358,10 +267,8 @@ export class Frontend {
358
267
  cluster: cluster,
359
268
  });
360
269
  });
361
- // this.log.debug('Response:', debugStringify(data));
362
270
  res.json(devices);
363
271
  });
364
- // Endpoint to provide the cluster servers of the devices
365
272
  this.expressApp.get('/api/devices_clusters/:selectedPluginName/:selectedDeviceEndpoint', (req, res) => {
366
273
  const selectedPluginName = req.params.selectedPluginName;
367
274
  const selectedDeviceEndpoint = parseInt(req.params.selectedDeviceEndpoint, 10);
@@ -434,7 +341,6 @@ export class Frontend {
434
341
  });
435
342
  res.json(data);
436
343
  });
437
- // Endpoint to view the log
438
344
  this.expressApp.get('/api/view-log', async (req, res) => {
439
345
  this.log.debug('The frontend sent /api/log');
440
346
  try {
@@ -447,12 +353,10 @@ export class Frontend {
447
353
  res.status(500).send('Error reading log file');
448
354
  }
449
355
  });
450
- // Endpoint to download the matterbridge log
451
356
  this.expressApp.get('/api/download-mblog', async (req, res) => {
452
357
  this.log.debug('The frontend sent /api/download-mblog');
453
358
  try {
454
359
  await fs.access(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterbrideLoggerFile), fs.constants.F_OK);
455
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
456
360
  }
457
361
  catch (error) {
458
362
  fs.appendFile(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterbrideLoggerFile), 'Enable the log on file in the settings to enable the file logger');
@@ -464,12 +368,10 @@ export class Frontend {
464
368
  }
465
369
  });
466
370
  });
467
- // Endpoint to download the matter log
468
371
  this.expressApp.get('/api/download-mjlog', async (req, res) => {
469
372
  this.log.debug('The frontend sent /api/download-mjlog');
470
373
  try {
471
374
  await fs.access(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterLoggerFile), fs.constants.F_OK);
472
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
473
375
  }
474
376
  catch (error) {
475
377
  fs.appendFile(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterLoggerFile), 'Enable the log on file in the settings to enable the file logger');
@@ -481,7 +383,6 @@ export class Frontend {
481
383
  }
482
384
  });
483
385
  });
484
- // Endpoint to download the matter storage file
485
386
  this.expressApp.get('/api/download-mjstorage', async (req, res) => {
486
387
  this.log.debug('The frontend sent /api/download-mjstorage');
487
388
  await createZip(path.join(os.tmpdir(), `matterbridge.${this.matterbridge.matterStorageName}.zip`), path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterStorageName));
@@ -492,7 +393,6 @@ export class Frontend {
492
393
  }
493
394
  });
494
395
  });
495
- // Endpoint to download the matterbridge storage directory
496
396
  this.expressApp.get('/api/download-mbstorage', async (req, res) => {
497
397
  this.log.debug('The frontend sent /api/download-mbstorage');
498
398
  await createZip(path.join(os.tmpdir(), `matterbridge.${this.matterbridge.nodeStorageName}.zip`), path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.nodeStorageName));
@@ -503,7 +403,6 @@ export class Frontend {
503
403
  }
504
404
  });
505
405
  });
506
- // Endpoint to download the matterbridge plugin directory
507
406
  this.expressApp.get('/api/download-pluginstorage', async (req, res) => {
508
407
  this.log.debug('The frontend sent /api/download-pluginstorage');
509
408
  await createZip(path.join(os.tmpdir(), `matterbridge.pluginstorage.zip`), this.matterbridge.matterbridgePluginDirectory);
@@ -514,11 +413,9 @@ export class Frontend {
514
413
  }
515
414
  });
516
415
  });
517
- // Endpoint to download the matterbridge plugin config files
518
416
  this.expressApp.get('/api/download-pluginconfig', async (req, res) => {
519
417
  this.log.debug('The frontend sent /api/download-pluginconfig');
520
418
  await createZip(path.join(os.tmpdir(), `matterbridge.pluginconfig.zip`), path.relative(process.cwd(), path.join(this.matterbridge.matterbridgeDirectory, '*.config.json')));
521
- // 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')));
522
419
  res.download(path.join(os.tmpdir(), `matterbridge.pluginconfig.zip`), `matterbridge.pluginconfig.zip`, (error) => {
523
420
  if (error) {
524
421
  this.log.error(`Error downloading file matterbridge.pluginstorage.zip: ${error instanceof Error ? error.message : error}`);
@@ -526,7 +423,6 @@ export class Frontend {
526
423
  }
527
424
  });
528
425
  });
529
- // Endpoint to download the matterbridge plugin config files
530
426
  this.expressApp.get('/api/download-backup', async (req, res) => {
531
427
  this.log.debug('The frontend sent /api/download-backup');
532
428
  res.download(path.join(os.tmpdir(), `matterbridge.backup.zip`), `matterbridge.backup.zip`, (error) => {
@@ -536,7 +432,6 @@ export class Frontend {
536
432
  }
537
433
  });
538
434
  });
539
- // Endpoint to receive commands
540
435
  this.expressApp.post('/api/command/:command/:param', express.json(), async (req, res) => {
541
436
  const command = req.params.command;
542
437
  let param = req.params.param;
@@ -546,15 +441,13 @@ export class Frontend {
546
441
  return;
547
442
  }
548
443
  this.log.debug(`Received frontend command: ${command}:${param}`);
549
- // Handle the command setpassword from Settings
550
444
  if (command === 'setpassword') {
551
- const password = param.slice(1, -1); // Remove the first and last characters
445
+ const password = param.slice(1, -1);
552
446
  this.log.debug('setpassword', param, password);
553
447
  await this.matterbridge.nodeContext?.set('password', password);
554
448
  res.json({ message: 'Command received' });
555
449
  return;
556
450
  }
557
- // Handle the command setbridgemode from Settings
558
451
  if (command === 'setbridgemode') {
559
452
  this.log.debug(`setbridgemode: ${param}`);
560
453
  this.wssSendRestartRequired();
@@ -562,7 +455,6 @@ export class Frontend {
562
455
  res.json({ message: 'Command received' });
563
456
  return;
564
457
  }
565
- // Handle the command backup from Settings
566
458
  if (command === 'backup') {
567
459
  this.log.notice(`Prepairing the backup...`);
568
460
  await createZip(path.join(os.tmpdir(), `matterbridge.backup.zip`), path.join(this.matterbridge.matterbridgeDirectory), path.join(this.matterbridge.matterbridgePluginDirectory));
@@ -570,26 +462,25 @@ export class Frontend {
570
462
  res.json({ message: 'Command received' });
571
463
  return;
572
464
  }
573
- // Handle the command setmbloglevel from Settings
574
465
  if (command === 'setmbloglevel') {
575
466
  this.log.debug('Matterbridge log level:', param);
576
467
  if (param === 'Debug') {
577
- this.log.logLevel = "debug" /* LogLevel.DEBUG */;
468
+ this.log.logLevel = "debug";
578
469
  }
579
470
  else if (param === 'Info') {
580
- this.log.logLevel = "info" /* LogLevel.INFO */;
471
+ this.log.logLevel = "info";
581
472
  }
582
473
  else if (param === 'Notice') {
583
- this.log.logLevel = "notice" /* LogLevel.NOTICE */;
474
+ this.log.logLevel = "notice";
584
475
  }
585
476
  else if (param === 'Warn') {
586
- this.log.logLevel = "warn" /* LogLevel.WARN */;
477
+ this.log.logLevel = "warn";
587
478
  }
588
479
  else if (param === 'Error') {
589
- this.log.logLevel = "error" /* LogLevel.ERROR */;
480
+ this.log.logLevel = "error";
590
481
  }
591
482
  else if (param === 'Fatal') {
592
- this.log.logLevel = "fatal" /* LogLevel.FATAL */;
483
+ this.log.logLevel = "fatal";
593
484
  }
594
485
  await this.matterbridge.nodeContext?.set('matterbridgeLogLevel', this.log.logLevel);
595
486
  this.matterbridge.log.logLevel = this.log.logLevel;
@@ -599,13 +490,12 @@ export class Frontend {
599
490
  for (const plugin of this.matterbridge.plugins) {
600
491
  if (!plugin.platform || !plugin.platform.config)
601
492
  continue;
602
- plugin.platform.log.logLevel = plugin.platform.config.debug ? "debug" /* LogLevel.DEBUG */ : this.log.logLevel;
603
- await plugin.platform.onChangeLoggerLevel(plugin.platform.config.debug ? "debug" /* LogLevel.DEBUG */ : this.log.logLevel);
493
+ plugin.platform.log.logLevel = plugin.platform.config.debug ? "debug" : this.log.logLevel;
494
+ await plugin.platform.onChangeLoggerLevel(plugin.platform.config.debug ? "debug" : this.log.logLevel);
604
495
  }
605
496
  res.json({ message: 'Command received' });
606
497
  return;
607
498
  }
608
- // Handle the command setmbloglevel from Settings
609
499
  if (command === 'setmjloglevel') {
610
500
  this.log.debug('Matter.js log level:', param);
611
501
  if (param === 'Debug') {
@@ -630,34 +520,30 @@ export class Frontend {
630
520
  res.json({ message: 'Command received' });
631
521
  return;
632
522
  }
633
- // Handle the command setmdnsinterface from Settings
634
523
  if (command === 'setmdnsinterface') {
635
- param = param.slice(1, -1); // Remove the first and last characters *mdns*
524
+ param = param.slice(1, -1);
636
525
  this.matterbridge.matterbridgeInformation.mattermdnsinterface = param;
637
526
  this.log.debug('Matter.js mdns interface:', param === '' ? 'All interfaces' : param);
638
527
  await this.matterbridge.nodeContext?.set('mattermdnsinterface', param);
639
528
  res.json({ message: 'Command received' });
640
529
  return;
641
530
  }
642
- // Handle the command setipv4address from Settings
643
531
  if (command === 'setipv4address') {
644
- param = param.slice(1, -1); // Remove the first and last characters *ip*
532
+ param = param.slice(1, -1);
645
533
  this.matterbridge.matterbridgeInformation.matteripv4address = param;
646
534
  this.log.debug('Matter.js ipv4 address:', param === '' ? 'All ipv4 addresses' : param);
647
535
  await this.matterbridge.nodeContext?.set('matteripv4address', param);
648
536
  res.json({ message: 'Command received' });
649
537
  return;
650
538
  }
651
- // Handle the command setipv6address from Settings
652
539
  if (command === 'setipv6address') {
653
- param = param.slice(1, -1); // Remove the first and last characters *ip*
540
+ param = param.slice(1, -1);
654
541
  this.matterbridge.matterbridgeInformation.matteripv6address = param;
655
542
  this.log.debug('Matter.js ipv6 address:', param === '' ? 'All ipv6 addresses' : param);
656
543
  await this.matterbridge.nodeContext?.set('matteripv6address', param);
657
544
  res.json({ message: 'Command received' });
658
545
  return;
659
546
  }
660
- // Handle the command setmatterport from Settings
661
547
  if (command === 'setmatterport') {
662
548
  const port = Math.min(Math.max(parseInt(param), 5540), 5560);
663
549
  this.matterbridge.matterbridgeInformation.matterPort = port;
@@ -666,7 +552,6 @@ export class Frontend {
666
552
  res.json({ message: 'Command received' });
667
553
  return;
668
554
  }
669
- // Handle the command setmatterdiscriminator from Settings
670
555
  if (command === 'setmatterdiscriminator') {
671
556
  const discriminator = Math.min(Math.max(parseInt(param), 1000), 4095);
672
557
  this.matterbridge.matterbridgeInformation.matterDiscriminator = discriminator;
@@ -675,7 +560,6 @@ export class Frontend {
675
560
  res.json({ message: 'Command received' });
676
561
  return;
677
562
  }
678
- // Handle the command setmatterpasscode from Settings
679
563
  if (command === 'setmatterpasscode') {
680
564
  const passcode = Math.min(Math.max(parseInt(param), 10000000), 90000000);
681
565
  this.matterbridge.matterbridgeInformation.matterPasscode = passcode;
@@ -684,20 +568,17 @@ export class Frontend {
684
568
  res.json({ message: 'Command received' });
685
569
  return;
686
570
  }
687
- // Handle the command setmbloglevel from Settings
688
571
  if (command === 'setmblogfile') {
689
572
  this.log.debug('Matterbridge file log:', param);
690
573
  this.matterbridge.matterbridgeInformation.fileLogger = param === 'true';
691
574
  await this.matterbridge.nodeContext?.set('matterbridgeFileLog', param === 'true');
692
- // Create the file logger for matterbridge
693
575
  if (param === 'true')
694
- AnsiLogger.setGlobalLogfile(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterbrideLoggerFile), "debug" /* LogLevel.DEBUG */, true);
576
+ AnsiLogger.setGlobalLogfile(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterbrideLoggerFile), "debug", true);
695
577
  else
696
578
  AnsiLogger.setGlobalLogfile(undefined);
697
579
  res.json({ message: 'Command received' });
698
580
  return;
699
581
  }
700
- // Handle the command setmbloglevel from Settings
701
582
  if (command === 'setmjlogfile') {
702
583
  this.log.debug('Matter file log:', param);
703
584
  this.matterbridge.matterbridgeInformation.matterFileLogger = param === 'true';
@@ -724,57 +605,40 @@ export class Frontend {
724
605
  res.json({ message: 'Command received' });
725
606
  return;
726
607
  }
727
- // Handle the command unregister from Settings
728
608
  if (command === 'unregister') {
729
609
  await this.matterbridge.unregisterAndShutdownProcess();
730
610
  res.json({ message: 'Command received' });
731
611
  return;
732
612
  }
733
- // Handle the command reset from Settings
734
613
  if (command === 'reset') {
735
614
  await this.matterbridge.shutdownProcessAndReset();
736
615
  res.json({ message: 'Command received' });
737
616
  return;
738
617
  }
739
- // Handle the command factoryreset from Settings
740
618
  if (command === 'factoryreset') {
741
619
  await this.matterbridge.shutdownProcessAndFactoryReset();
742
620
  res.json({ message: 'Command received' });
743
621
  return;
744
622
  }
745
- // Handle the command shutdown from Header
746
623
  if (command === 'shutdown') {
747
624
  await this.matterbridge.shutdownProcess();
748
625
  res.json({ message: 'Command received' });
749
626
  return;
750
627
  }
751
- // Handle the command restart from Header
752
628
  if (command === 'restart') {
753
629
  await this.matterbridge.restartProcess();
754
630
  res.json({ message: 'Command received' });
755
631
  return;
756
632
  }
757
- // Handle the command update from Header
758
633
  if (command === 'update') {
759
- this.log.info('Updating matterbridge...');
760
- try {
761
- await this.matterbridge.spawnCommand('npm', ['install', '-g', 'matterbridge', '--omit=dev', '--verbose']);
762
- this.log.info('Matterbridge has been updated. Full restart required.');
763
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
764
- }
765
- catch (error) {
766
- this.log.error('Error updating matterbridge');
767
- }
768
634
  await this.matterbridge.updateProcess();
769
635
  this.wssSendRestartRequired();
770
636
  res.json({ message: 'Command received' });
771
637
  return;
772
638
  }
773
- // Handle the command saveconfig from Home
774
639
  if (command === 'saveconfig') {
775
640
  param = param.replace(/\*/g, '\\');
776
641
  this.log.info(`Saving config for plugin ${plg}${param}${nf}...`);
777
- // console.log('Req.body:', JSON.stringify(req.body, null, 2));
778
642
  if (!this.matterbridge.plugins.has(param)) {
779
643
  this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
780
644
  }
@@ -788,58 +652,49 @@ export class Frontend {
788
652
  res.json({ message: 'Command received' });
789
653
  return;
790
654
  }
791
- // Handle the command installplugin from Home
792
655
  if (command === 'installplugin') {
793
656
  param = param.replace(/\*/g, '\\');
794
657
  this.log.info(`Installing plugin ${plg}${param}${nf}...`);
795
658
  try {
796
659
  await this.matterbridge.spawnCommand('npm', ['install', '-g', param, '--omit=dev', '--verbose']);
797
660
  this.log.info(`Plugin ${plg}${param}${nf} installed. Full restart required.`);
798
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
799
661
  }
800
662
  catch (error) {
801
663
  this.log.error(`Error installing plugin ${plg}${param}${er}`);
802
664
  }
803
665
  this.wssSendRestartRequired();
804
666
  param = param.split('@')[0];
805
- // Also add the plugin to matterbridge so no return!
806
667
  if (param === 'matterbridge') {
807
- // 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
808
668
  res.json({ message: 'Command received' });
809
669
  return;
810
670
  }
811
671
  }
812
- // Handle the command addplugin from Home
813
672
  if (command === 'addplugin' || command === 'installplugin') {
814
673
  param = param.replace(/\*/g, '\\');
815
674
  const plugin = await this.matterbridge.plugins.add(param);
816
675
  if (plugin) {
817
676
  if (this.matterbridge.bridgeMode === 'childbridge') {
818
- // 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
819
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
820
677
  this.matterbridge.createDynamicPlugin(plugin, true);
821
678
  }
822
- this.matterbridge.plugins.load(plugin, true, 'The plugin has been added', true); // No await do it in the background
679
+ this.matterbridge.plugins.load(plugin, true, 'The plugin has been added', true);
823
680
  }
824
681
  res.json({ message: 'Command received' });
825
682
  this.wssSendRefreshRequired();
826
683
  return;
827
684
  }
828
- // Handle the command removeplugin from Home
829
685
  if (command === 'removeplugin') {
830
686
  if (!this.matterbridge.plugins.has(param)) {
831
687
  this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
832
688
  }
833
689
  else {
834
690
  const plugin = this.matterbridge.plugins.get(param);
835
- await this.matterbridge.plugins.shutdown(plugin, 'The plugin has been removed.', true); // This will also close the server node in childbridge mode
691
+ await this.matterbridge.plugins.shutdown(plugin, 'The plugin has been removed.', true);
836
692
  await this.matterbridge.plugins.remove(param);
837
693
  }
838
694
  res.json({ message: 'Command received' });
839
695
  this.wssSendRefreshRequired();
840
696
  return;
841
697
  }
842
- // Handle the command enableplugin from Home
843
698
  if (command === 'enableplugin') {
844
699
  if (!this.matterbridge.plugins.has(param)) {
845
700
  this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
@@ -857,17 +712,15 @@ export class Frontend {
857
712
  plugin.addedDevices = undefined;
858
713
  await this.matterbridge.plugins.enable(param);
859
714
  if (this.matterbridge.bridgeMode === 'childbridge' && plugin.type === 'DynamicPlatform') {
860
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
861
715
  this.matterbridge.createDynamicPlugin(plugin, true);
862
716
  }
863
- 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
717
+ this.matterbridge.plugins.load(plugin, true, 'The plugin has been enabled', true);
864
718
  }
865
719
  }
866
720
  res.json({ message: 'Command received' });
867
721
  this.wssSendRefreshRequired();
868
722
  return;
869
723
  }
870
- // Handle the command disableplugin from Home
871
724
  if (command === 'disableplugin') {
872
725
  if (!this.matterbridge.plugins.has(param)) {
873
726
  this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
@@ -875,7 +728,7 @@ export class Frontend {
875
728
  else {
876
729
  const plugin = this.matterbridge.plugins.get(param);
877
730
  if (plugin && plugin.enabled) {
878
- await this.matterbridge.plugins.shutdown(plugin, 'The plugin has been disabled.', true); // This will also close the server node in childbridge mode
731
+ await this.matterbridge.plugins.shutdown(plugin, 'The plugin has been disabled.', true);
879
732
  await this.matterbridge.plugins.disable(param);
880
733
  }
881
734
  }
@@ -884,7 +737,6 @@ export class Frontend {
884
737
  return;
885
738
  }
886
739
  });
887
- // Fallback for routing (must be the last route)
888
740
  this.expressApp.get('*', (req, res) => {
889
741
  this.log.debug('The frontend sent:', req.url);
890
742
  this.log.debug('Response send file:', path.join(this.matterbridge.rootDirectory, 'frontend/build/index.html'));
@@ -893,29 +745,24 @@ export class Frontend {
893
745
  this.log.debug(`Frontend initialized on port ${YELLOW}${this.port}${db} static ${UNDERLINE}${path.join(this.matterbridge.rootDirectory, 'frontend/build')}${UNDERLINEOFF}${rs}`);
894
746
  }
895
747
  async stop() {
896
- // Close the http server
897
748
  if (this.httpServer) {
898
749
  this.httpServer.close();
899
750
  this.httpServer.removeAllListeners();
900
751
  this.httpServer = undefined;
901
752
  this.log.debug('Frontend http server closed successfully');
902
753
  }
903
- // Close the https server
904
754
  if (this.httpsServer) {
905
755
  this.httpsServer.close();
906
756
  this.httpsServer.removeAllListeners();
907
757
  this.httpsServer = undefined;
908
758
  this.log.debug('Frontend https server closed successfully');
909
759
  }
910
- // Remove listeners from the express app
911
760
  if (this.expressApp) {
912
761
  this.expressApp.removeAllListeners();
913
762
  this.expressApp = undefined;
914
763
  this.log.debug('Frontend app closed successfully');
915
764
  }
916
- // Close the WebSocket server
917
765
  if (this.webSocketServer) {
918
- // Close all active connections
919
766
  this.webSocketServer.clients.forEach((client) => {
920
767
  if (client.readyState === WebSocket.OPEN) {
921
768
  client.close();
@@ -931,23 +778,35 @@ export class Frontend {
931
778
  });
932
779
  this.webSocketServer = undefined;
933
780
  }
934
- // Stop the memory dump interval
935
781
  if (hasParameter('memorydump')) {
936
- this.stopMemoryDump();
782
+ this.stopCpuMemoryDump();
937
783
  }
938
784
  }
939
- // Function to format bytes to KB or MB
940
785
  formatMemoryUsage = (bytes) => {
941
786
  const kb = bytes / 1024;
942
787
  const mb = kb / 1024;
943
788
  return mb >= 1 ? `${mb.toFixed(2)} MB` : `${kb.toFixed(2)} KB`;
944
789
  };
945
- startMemoryDump() {
790
+ startCpuMemoryDump() {
946
791
  clearInterval(this.memoryInterval);
947
792
  clearTimeout(this.memoryTimeout);
948
793
  const interval = () => {
794
+ const currCpus = os.cpus();
795
+ if (currCpus.length !== this.prevCpus.length) {
796
+ this.prevCpus = currCpus;
797
+ }
798
+ let totalIdle = 0, totalTick = 0;
799
+ this.prevCpus.forEach((prevCpu, i) => {
800
+ const currCpu = currCpus[i];
801
+ const idleDiff = currCpu.times.idle - prevCpu.times.idle;
802
+ const totalDiff = Object.keys(currCpu.times).reduce((acc, key) => acc + (currCpu.times[key] - prevCpu.times[key]), 0);
803
+ totalIdle += idleDiff;
804
+ totalTick += totalDiff;
805
+ });
806
+ const cpuUsage = (100 - (totalIdle / totalTick) * 100).toFixed(2);
807
+ this.prevCpus = currCpus;
949
808
  const memoryUsageRaw = process.memoryUsage();
950
- this.memoryData.push(memoryUsageRaw);
809
+ this.memoryData.push({ ...memoryUsageRaw, cpu: cpuUsage });
951
810
  const memoryUsage = {
952
811
  rss: this.formatMemoryUsage(memoryUsageRaw.rss),
953
812
  heapTotal: this.formatMemoryUsage(memoryUsageRaw.heapTotal),
@@ -955,17 +814,17 @@ export class Frontend {
955
814
  external: this.formatMemoryUsage(memoryUsageRaw.external),
956
815
  arrayBuffers: this.formatMemoryUsage(memoryUsageRaw.arrayBuffers),
957
816
  };
958
- this.log.debug(`***Memory usage rss ${CYAN}${memoryUsage.rss}${db} heapTotal ${CYAN}${memoryUsage.heapTotal}${db} heapUsed ${CYAN}${memoryUsage.heapUsed}${db} external ${memoryUsage.external} arrayBuffers ${memoryUsage.arrayBuffers}`);
817
+ this.log.debug(`***Cpu usage ${CYAN}${cpuUsage.padStart(6, ' ')} %${db} - Memory usage rss ${CYAN}${memoryUsage.rss}${db} heapTotal ${CYAN}${memoryUsage.heapTotal}${db} heapUsed ${CYAN}${memoryUsage.heapUsed}${db} external ${memoryUsage.external} arrayBuffers ${memoryUsage.arrayBuffers}`);
959
818
  };
960
819
  interval();
961
- this.memoryInterval = setInterval(interval, getIntParameter('memorydump') ?? 1000);
820
+ this.memoryInterval = setInterval(interval, getIntParameter('memoryinterval') ?? 1000);
962
821
  this.memoryInterval.unref();
963
822
  this.memoryTimeout = setTimeout(() => {
964
- this.stopMemoryDump();
965
- }, 360000);
823
+ this.stopCpuMemoryDump();
824
+ }, getIntParameter('memorytimeout') ?? 600000);
966
825
  this.memoryTimeout.unref();
967
826
  }
968
- stopMemoryDump() {
827
+ stopCpuMemoryDump() {
969
828
  clearInterval(this.memoryInterval);
970
829
  this.memoryInterval = undefined;
971
830
  clearTimeout(this.memoryTimeout);
@@ -978,15 +837,14 @@ export class Frontend {
978
837
  external: this.formatMemoryUsage(memory.external),
979
838
  arrayBuffers: this.formatMemoryUsage(memory.arrayBuffers),
980
839
  };
981
- // eslint-disable-next-line no-console
982
- console.log(`${YELLOW}Memory usage${db} rss ${CYAN}${memoryUsage.rss}${db} heapTotal ${CYAN}${memoryUsage.heapTotal}${db} heapUsed ${CYAN}${memoryUsage.heapUsed}${db} external ${memoryUsage.external} arrayBuffers ${memoryUsage.arrayBuffers}${rs}`);
840
+ console.log(`${YELLOW}Cpu usage${db} ${CYAN}${memory.cpu.padStart(6, ' ')} %${db} - ${YELLOW}Memory usage${db} rss ${CYAN}${memoryUsage.rss}${db} heapTotal ${CYAN}${memoryUsage.heapTotal}${db} heapUsed ${CYAN}${memoryUsage.heapUsed}${db} external ${memoryUsage.external} arrayBuffers ${memoryUsage.arrayBuffers}${rs}`);
983
841
  }
842
+ this.memoryData = [];
843
+ this.prevCpus = [];
984
844
  }
985
- /**
986
- * Retrieves the api settings.
987
- * @returns {Promise<object>} A promise that resolve in the api settings object.
988
- */
989
845
  async getApiSettings() {
846
+ this.matterbridge.systemInformation.rss = this.formatMemoryUsage(process.memoryUsage().rss);
847
+ this.matterbridge.systemInformation.heap = this.formatMemoryUsage(process.memoryUsage().heapUsed) + ' / ' + this.formatMemoryUsage(process.memoryUsage().heapTotal);
990
848
  this.matterbridge.matterbridgeInformation.bridgeMode = this.matterbridge.bridgeMode;
991
849
  this.matterbridge.matterbridgeInformation.restartMode = this.matterbridge.restartMode;
992
850
  this.matterbridge.matterbridgeInformation.loggerLevel = this.matterbridge.log.logLevel;
@@ -1005,11 +863,6 @@ export class Frontend {
1005
863
  this.matterbridge.matterbridgeInformation.profile = this.matterbridge.profile;
1006
864
  return { systemInformation: this.matterbridge.systemInformation, matterbridgeInformation: this.matterbridge.matterbridgeInformation };
1007
865
  }
1008
- /**
1009
- * Retrieves the cluster text description from a given device.
1010
- * @param {MatterbridgeDevice} device - The MatterbridgeDevice object.
1011
- * @returns {string} The attributes description of the cluster servers in the device.
1012
- */
1013
866
  getClusterTextFromDevice(device) {
1014
867
  const getAttribute = (device, cluster, attribute) => {
1015
868
  let value = undefined;
@@ -1048,7 +901,6 @@ export class Frontend {
1048
901
  };
1049
902
  let attributes = '';
1050
903
  device.forEachAttribute((clusterName, clusterId, attributeName, attributeId, attributeValue) => {
1051
- // console.log(`${device.deviceName} => Cluster: ${clusterName}-${clusterId} Attribute: ${attributeName}-${attributeId} Value(${typeof attributeValue}): ${attributeValue}`);
1052
904
  if (typeof attributeValue === 'undefined')
1053
905
  return;
1054
906
  if (clusterName === 'onOff' && attributeName === 'onOff')
@@ -1126,13 +978,8 @@ export class Frontend {
1126
978
  if (clusterName === 'userLabel' && attributeName === 'labelList')
1127
979
  attributes += `${getUserLabel(device)} `;
1128
980
  });
1129
- // console.log(`${device.deviceName}.forEachAttribute: ${attributes}`);
1130
981
  return attributes.trimStart().trimEnd();
1131
982
  }
1132
- /**
1133
- * Retrieves the base registered plugins sanitized for res.json().
1134
- * @returns {BaseRegisteredPlugin[]} An array of BaseRegisteredPlugin.
1135
- */
1136
983
  getBaseRegisteredPlugins() {
1137
984
  const baseRegisteredPlugins = [];
1138
985
  for (const plugin of this.matterbridge.plugins) {
@@ -1163,14 +1010,6 @@ export class Frontend {
1163
1010
  }
1164
1011
  return baseRegisteredPlugins;
1165
1012
  }
1166
- /**
1167
- * Handles incoming websocket messages for the Matterbridge.
1168
- *
1169
- * @param {Matterbridge} this - The Matterbridge instance.
1170
- * @param {WebSocket} client - The websocket client that sent the message.
1171
- * @param {WebSocket.RawData} message - The raw data of the message received from the client.
1172
- * @returns {Promise<void>} A promise that resolves when the message has been handled.
1173
- */
1174
1013
  async wsMessageHandler(client, message) {
1175
1014
  let data;
1176
1015
  try {
@@ -1258,10 +1097,8 @@ export class Frontend {
1258
1097
  else if (data.method === '/api/devices') {
1259
1098
  const devices = [];
1260
1099
  this.matterbridge.devices.forEach(async (device) => {
1261
- // Filter by pluginName if provided
1262
1100
  if (data.params.pluginName && data.params.pluginName !== device.plugin)
1263
1101
  return;
1264
- // Check if the device has the required properties
1265
1102
  if (!device.plugin || !device.name || !device.deviceName || !device.serialNumber || !device.uniqueId)
1266
1103
  return;
1267
1104
  const cluster = this.getClusterTextFromDevice(device);
@@ -1344,7 +1181,6 @@ export class Frontend {
1344
1181
  });
1345
1182
  endpointServer.getChildEndpoints().forEach((childEndpoint) => {
1346
1183
  deviceTypes = [];
1347
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1348
1184
  const name = childEndpoint.endpoint?.id;
1349
1185
  const clusterServers = childEndpoint.getAllClusterServers();
1350
1186
  clusterServers.forEach((clusterServer) => {
@@ -1427,73 +1263,44 @@ export class Frontend {
1427
1263
  return;
1428
1264
  }
1429
1265
  }
1430
- /**
1431
- * Sends a WebSocket message to all connected clients. The function is called by AnsiLogger.setGlobalCallback.
1432
- *
1433
- * @param {string} level - The logger level of the message: debug info notice warn error fatal...
1434
- * @param {string} time - The time string of the message
1435
- * @param {string} name - The logger name of the message
1436
- * @param {string} message - The content of the message.
1437
- */
1438
1266
  wssSendMessage(level, time, name, message) {
1439
1267
  if (!level || !time || !name || !message)
1440
1268
  return;
1441
- // Remove ANSI escape codes from the message
1442
- // eslint-disable-next-line no-control-regex
1443
1269
  message = message.replace(/\x1B\[[0-9;]*[m|s|u|K]/g, '');
1444
- // Remove leading asterisks from the message
1445
1270
  message = message.replace(/^\*+/, '');
1446
- // Replace all occurrences of \t and \n
1447
1271
  message = message.replace(/[\t\n]/g, '');
1448
- // Remove non-printable characters
1449
- // eslint-disable-next-line no-control-regex
1450
1272
  message = message.replace(/[\x00-\x1F\x7F]/g, '');
1451
- // Replace all occurrences of \" with "
1452
1273
  message = message.replace(/\\"/g, '"');
1453
- // Define the maximum allowed length for continuous characters without a space
1454
1274
  const maxContinuousLength = 100;
1455
1275
  const keepStartLength = 20;
1456
1276
  const keepEndLength = 20;
1457
- // Split the message into words
1458
1277
  message = message
1459
1278
  .split(' ')
1460
1279
  .map((word) => {
1461
- // If the word length exceeds the max continuous length, insert spaces and truncate
1462
1280
  if (word.length > maxContinuousLength) {
1463
1281
  return word.slice(0, keepStartLength) + ' ... ' + word.slice(-keepEndLength);
1464
1282
  }
1465
1283
  return word;
1466
1284
  })
1467
1285
  .join(' ');
1468
- // Send the message to all connected clients
1469
1286
  this.webSocketServer?.clients.forEach((client) => {
1470
1287
  if (client.readyState === WebSocket.OPEN) {
1471
1288
  client.send(JSON.stringify({ id: WS_ID_LOG, src: 'Matterbridge', level, time, name, message }));
1472
1289
  }
1473
1290
  });
1474
1291
  }
1475
- /**
1476
- * Sends a need to refresh WebSocket message to all connected clients.
1477
- *
1478
- */
1479
1292
  wssSendRefreshRequired() {
1480
1293
  this.log.debug('Sending a refresh required message to all connected clients');
1481
1294
  this.matterbridge.matterbridgeInformation.refreshRequired = true;
1482
- // Send the message to all connected clients
1483
1295
  this.webSocketServer?.clients.forEach((client) => {
1484
1296
  if (client.readyState === WebSocket.OPEN) {
1485
1297
  client.send(JSON.stringify({ id: WS_ID_REFRESH_NEEDED, src: 'Matterbridge', dst: 'Frontend', method: 'refresh_required', params: {} }));
1486
1298
  }
1487
1299
  });
1488
1300
  }
1489
- /**
1490
- * Sends a need to restart WebSocket message to all connected clients.
1491
- *
1492
- */
1493
1301
  wssSendRestartRequired() {
1494
1302
  this.log.debug('Sending a restart required message to all connected clients');
1495
1303
  this.matterbridge.matterbridgeInformation.restartRequired = true;
1496
- // Send the message to all connected clients
1497
1304
  this.webSocketServer?.clients.forEach((client) => {
1498
1305
  if (client.readyState === WebSocket.OPEN) {
1499
1306
  client.send(JSON.stringify({ id: WS_ID_RESTART_NEEDED, src: 'Matterbridge', dst: 'Frontend', method: 'restart_required', params: {} }));
@@ -1501,4 +1308,3 @@ export class Frontend {
1501
1308
  });
1502
1309
  }
1503
1310
  }
1504
- //# sourceMappingURL=frontend.js.map