matterbridge 2.2.0-dev.5 → 2.2.0-dev.7

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 (127) hide show
  1. package/CHANGELOG.md +1 -8
  2. package/dist/cli.js +2 -37
  3. package/dist/cluster/export.js +0 -2
  4. package/dist/defaultConfigSchema.js +0 -23
  5. package/dist/deviceManager.js +1 -94
  6. package/dist/frontend.js +42 -265
  7. package/dist/index.js +2 -29
  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 +0 -2
  14. package/dist/matter/types.js +1 -3
  15. package/dist/matterbridge.js +51 -720
  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 +9 -118
  22. package/dist/matterbridgePlatform.js +7 -140
  23. package/dist/matterbridgeTypes.js +0 -24
  24. package/dist/pluginManager.js +3 -229
  25. package/dist/shelly.js +33 -136
  26. package/dist/storage/export.js +0 -1
  27. package/dist/update.js +0 -45
  28. package/dist/utils/colorUtils.js +2 -205
  29. package/dist/utils/copyDirectory.js +1 -37
  30. package/dist/utils/createZip.js +2 -42
  31. package/dist/utils/deepCopy.js +0 -40
  32. package/dist/utils/deepEqual.js +1 -65
  33. package/dist/utils/export.js +0 -1
  34. package/dist/utils/isvalid.js +0 -86
  35. package/dist/utils/network.js +5 -77
  36. package/dist/utils/parameter.js +0 -41
  37. package/dist/utils/wait.js +5 -48
  38. package/frontend/build/asset-manifest.json +3 -3
  39. package/frontend/build/index.html +1 -1
  40. package/frontend/build/static/js/{main.f60aae10.js → main.8240902c.js} +3 -3
  41. package/frontend/build/static/js/main.8240902c.js.map +1 -0
  42. package/npm-shrinkwrap.json +44 -44
  43. package/package.json +2 -2
  44. package/dist/cli.d.ts +0 -28
  45. package/dist/cli.d.ts.map +0 -1
  46. package/dist/cli.js.map +0 -1
  47. package/dist/cluster/export.d.ts.map +0 -1
  48. package/dist/cluster/export.js.map +0 -1
  49. package/dist/defaultConfigSchema.d.ts.map +0 -1
  50. package/dist/defaultConfigSchema.js.map +0 -1
  51. package/dist/deviceManager.d.ts +0 -109
  52. package/dist/deviceManager.d.ts.map +0 -1
  53. package/dist/deviceManager.js.map +0 -1
  54. package/dist/frontend.d.ts +0 -172
  55. package/dist/frontend.d.ts.map +0 -1
  56. package/dist/frontend.js.map +0 -1
  57. package/dist/index.d.ts.map +0 -1
  58. package/dist/index.js.map +0 -1
  59. package/dist/logger/export.d.ts.map +0 -1
  60. package/dist/logger/export.js.map +0 -1
  61. package/dist/matter/behaviors.d.ts.map +0 -1
  62. package/dist/matter/behaviors.js.map +0 -1
  63. package/dist/matter/clusters.d.ts.map +0 -1
  64. package/dist/matter/clusters.js.map +0 -1
  65. package/dist/matter/devices.d.ts.map +0 -1
  66. package/dist/matter/devices.js.map +0 -1
  67. package/dist/matter/endpoints.d.ts.map +0 -1
  68. package/dist/matter/endpoints.js.map +0 -1
  69. package/dist/matter/export.d.ts.map +0 -1
  70. package/dist/matter/export.js.map +0 -1
  71. package/dist/matter/types.d.ts.map +0 -1
  72. package/dist/matter/types.js.map +0 -1
  73. package/dist/matterbridge.d.ts +0 -410
  74. package/dist/matterbridge.d.ts.map +0 -1
  75. package/dist/matterbridge.js.map +0 -1
  76. package/dist/matterbridgeAccessoryPlatform.d.ts.map +0 -1
  77. package/dist/matterbridgeAccessoryPlatform.js.map +0 -1
  78. package/dist/matterbridgeBehaviors.d.ts +0 -148
  79. package/dist/matterbridgeBehaviors.d.ts.map +0 -1
  80. package/dist/matterbridgeBehaviors.js.map +0 -1
  81. package/dist/matterbridgeDeviceTypes.d.ts.map +0 -1
  82. package/dist/matterbridgeDeviceTypes.js.map +0 -1
  83. package/dist/matterbridgeDynamicPlatform.d.ts.map +0 -1
  84. package/dist/matterbridgeDynamicPlatform.js.map +0 -1
  85. package/dist/matterbridgeEndpoint.d.ts +0 -827
  86. package/dist/matterbridgeEndpoint.d.ts.map +0 -1
  87. package/dist/matterbridgeEndpoint.js.map +0 -1
  88. package/dist/matterbridgeEndpointHelpers.d.ts +0 -123
  89. package/dist/matterbridgeEndpointHelpers.d.ts.map +0 -1
  90. package/dist/matterbridgeEndpointHelpers.js.map +0 -1
  91. package/dist/matterbridgePlatform.d.ts +0 -159
  92. package/dist/matterbridgePlatform.d.ts.map +0 -1
  93. package/dist/matterbridgePlatform.js.map +0 -1
  94. package/dist/matterbridgeTypes.d.ts.map +0 -1
  95. package/dist/matterbridgeTypes.js.map +0 -1
  96. package/dist/pluginManager.d.ts +0 -236
  97. package/dist/pluginManager.d.ts.map +0 -1
  98. package/dist/pluginManager.js.map +0 -1
  99. package/dist/shelly.d.ts.map +0 -1
  100. package/dist/shelly.js.map +0 -1
  101. package/dist/storage/export.d.ts.map +0 -1
  102. package/dist/storage/export.js.map +0 -1
  103. package/dist/update.d.ts.map +0 -1
  104. package/dist/update.js.map +0 -1
  105. package/dist/utils/colorUtils.d.ts.map +0 -1
  106. package/dist/utils/colorUtils.js.map +0 -1
  107. package/dist/utils/copyDirectory.d.ts.map +0 -1
  108. package/dist/utils/copyDirectory.js.map +0 -1
  109. package/dist/utils/createZip.d.ts.map +0 -1
  110. package/dist/utils/createZip.js.map +0 -1
  111. package/dist/utils/deepCopy.d.ts.map +0 -1
  112. package/dist/utils/deepCopy.js.map +0 -1
  113. package/dist/utils/deepEqual.d.ts.map +0 -1
  114. package/dist/utils/deepEqual.js.map +0 -1
  115. package/dist/utils/export.d.ts.map +0 -1
  116. package/dist/utils/export.js.map +0 -1
  117. package/dist/utils/isvalid.d.ts.map +0 -1
  118. package/dist/utils/isvalid.js.map +0 -1
  119. package/dist/utils/network.d.ts.map +0 -1
  120. package/dist/utils/network.js.map +0 -1
  121. package/dist/utils/parameter.d.ts.map +0 -1
  122. package/dist/utils/parameter.js.map +0 -1
  123. package/dist/utils/wait.d.ts +0 -43
  124. package/dist/utils/wait.d.ts.map +0 -1
  125. package/dist/utils/wait.js.map +0 -1
  126. package/frontend/build/static/js/main.f60aae10.js.map +0 -1
  127. /package/frontend/build/static/js/{main.f60aae10.js.LICENSE.txt → main.8240902c.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.2
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 'node:http';
27
3
  import https from 'https';
28
4
  import express from 'express';
@@ -30,70 +6,19 @@ import WebSocket, { WebSocketServer } from 'ws';
30
6
  import os from 'node:os';
31
7
  import path from 'node:path';
32
8
  import { promises as fs } from 'node:fs';
33
- // AnsiLogger module
34
9
  import { AnsiLogger, stringify, debugStringify, CYAN, db, er, nf, rs, UNDERLINE, UNDERLINEOFF, wr, YELLOW } from './logger/export.js';
35
- // Matterbridge
36
10
  import { createZip, deepCopy, isValidNumber, isValidObject, isValidString } from './utils/export.js';
37
11
  import { plg } from './matterbridgeTypes.js';
38
12
  import { hasParameter } from './utils/export.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
- * Websocket message ID indicating a cpu update.
56
- * @constant {number}
57
- */
58
16
  export const WS_ID_CPU_UPDATE = 3;
59
- /**
60
- * Websocket message ID indicating a memory update.
61
- * @constant {number}
62
- */
63
17
  export const WS_ID_MEMORY_UPDATE = 4;
64
- /**
65
- * Websocket message ID indicating an uptime update.
66
- * @constant {number}
67
- */
68
18
  export const WS_ID_UPTIME_UPDATE = 5;
69
- /**
70
- * Websocket message ID indicating a memory update.
71
- * @constant {number}
72
- */
73
19
  export const WS_ID_SNACKBAR = 6;
74
- /**
75
- * Websocket message ID indicating a shelly system update.
76
- * check:
77
- * curl -k http://127.0.0.1:8101/api/updates/sys/check
78
- * perform:
79
- * curl -k http://127.0.0.1:8101/api/updates/sys/perform
80
- * @constant {number}
81
- */
82
20
  export const WS_ID_SHELLY_SYS_UPDATE = 100;
83
- /**
84
- * Websocket message ID indicating a shelly main update.
85
- * check:
86
- * curl -k http://127.0.0.1:8101/api/updates/main/check
87
- * perform:
88
- * curl -k http://127.0.0.1:8101/api/updates/main/perform
89
- * @constant {number}
90
- */
91
21
  export const WS_ID_SHELLY_MAIN_UPDATE = 101;
92
- /**
93
- * Initializes the frontend of Matterbridge.
94
- *
95
- * @param port The port number to run the frontend server on. Default is 8283.
96
- */
97
22
  export class Frontend {
98
23
  matterbridge;
99
24
  log;
@@ -110,7 +35,7 @@ export class Frontend {
110
35
  memoryTimeout;
111
36
  constructor(matterbridge) {
112
37
  this.matterbridge = matterbridge;
113
- this.log = new AnsiLogger({ logName: 'Frontend', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: hasParameter('debug') ? "debug" /* LogLevel.DEBUG */ : "info" /* LogLevel.INFO */ });
38
+ this.log = new AnsiLogger({ logName: 'Frontend', logTimestampFormat: 4, logLevel: hasParameter('debug') ? "debug" : "info" });
114
39
  }
115
40
  set logLevel(logLevel) {
116
41
  this.log.logLevel = logLevel;
@@ -118,21 +43,10 @@ export class Frontend {
118
43
  async start(port = 8283) {
119
44
  this.port = port;
120
45
  this.log.debug(`Initializing the frontend ${hasParameter('ssl') ? 'https' : 'http'} server on port ${YELLOW}${this.port}${db}`);
121
- // Create the express app that serves the frontend
122
46
  this.expressApp = express();
123
- // Log all requests to the server for debugging
124
- /*
125
- this.expressApp.use((req, res, next) => {
126
- this.log.debug(`Received request on expressApp: ${req.method} ${req.url}`);
127
- next();
128
- });
129
- */
130
- // Serve static files from '/static' endpoint
131
47
  this.expressApp.use(express.static(path.join(this.matterbridge.rootDirectory, 'frontend/build')));
132
48
  if (!hasParameter('ssl')) {
133
- // Create an HTTP server and attach the express app
134
49
  this.httpServer = createServer(this.expressApp);
135
- // Listen on the specified port
136
50
  if (hasParameter('ingress')) {
137
51
  this.httpServer.listen(this.port, '0.0.0.0', () => {
138
52
  this.log.info(`The frontend http server is listening on ${UNDERLINE}http://0.0.0.0:${this.port}${UNDERLINEOFF}${rs}`);
@@ -146,7 +60,6 @@ export class Frontend {
146
60
  this.log.info(`The frontend http server is listening on ${UNDERLINE}http://[${this.matterbridge.systemInformation.ipv6Address}]:${this.port}${UNDERLINEOFF}${rs}`);
147
61
  });
148
62
  }
149
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
150
63
  this.httpServer.on('error', (error) => {
151
64
  this.log.error(`Frontend http server error listening on ${this.port}`);
152
65
  switch (error.code) {
@@ -162,7 +75,6 @@ export class Frontend {
162
75
  });
163
76
  }
164
77
  else {
165
- // Load the SSL certificate, the private key and optionally the CA certificate
166
78
  let cert;
167
79
  try {
168
80
  cert = await fs.readFile(path.join(this.matterbridge.matterbridgeDirectory, 'certs/cert.pem'), 'utf8');
@@ -190,9 +102,7 @@ export class Frontend {
190
102
  this.log.info(`CA certificate file ${path.join(this.matterbridge.matterbridgeDirectory, 'certs/ca.pem')} not loaded: ${error}`);
191
103
  }
192
104
  const serverOptions = { cert, key, ca };
193
- // Create an HTTPS server with the SSL certificate and private key (ca is optional) and attach the express app
194
105
  this.httpsServer = https.createServer(serverOptions, this.expressApp);
195
- // Listen on the specified port
196
106
  if (hasParameter('ingress')) {
197
107
  this.httpsServer.listen(this.port, '0.0.0.0', () => {
198
108
  this.log.info(`The frontend https server is listening on ${UNDERLINE}https://0.0.0.0:${this.port}${UNDERLINEOFF}${rs}`);
@@ -206,7 +116,6 @@ export class Frontend {
206
116
  this.log.info(`The frontend https server is listening on ${UNDERLINE}https://[${this.matterbridge.systemInformation.ipv6Address}]:${this.port}${UNDERLINEOFF}${rs}`);
207
117
  });
208
118
  }
209
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
210
119
  this.httpsServer.on('error', (error) => {
211
120
  this.log.error(`Frontend https server error listening on ${this.port}`);
212
121
  switch (error.code) {
@@ -223,18 +132,16 @@ export class Frontend {
223
132
  }
224
133
  if (this.initializeError)
225
134
  return;
226
- // Create a WebSocket server and attach it to the http or https server
227
135
  const wssPort = this.port;
228
136
  const wssHost = hasParameter('ssl') ? `wss://${this.matterbridge.systemInformation.ipv4Address}:${wssPort}` : `ws://${this.matterbridge.systemInformation.ipv4Address}:${wssPort}`;
229
137
  this.webSocketServer = new WebSocketServer(hasParameter('ssl') ? { server: this.httpsServer } : { server: this.httpServer });
230
138
  this.webSocketServer.on('connection', (ws, request) => {
231
139
  const clientIp = request.socket.remoteAddress;
232
- // Set the global logger callback for the WebSocketServer
233
- let callbackLogLevel = "notice" /* LogLevel.NOTICE */;
234
- if (this.matterbridge.matterbridgeInformation.loggerLevel === "info" /* LogLevel.INFO */ || this.matterbridge.matterbridgeInformation.matterLoggerLevel === MatterLogLevel.INFO)
235
- callbackLogLevel = "info" /* LogLevel.INFO */;
236
- if (this.matterbridge.matterbridgeInformation.loggerLevel === "debug" /* LogLevel.DEBUG */ || this.matterbridge.matterbridgeInformation.matterLoggerLevel === MatterLogLevel.DEBUG)
237
- callbackLogLevel = "debug" /* LogLevel.DEBUG */;
140
+ let callbackLogLevel = "notice";
141
+ if (this.matterbridge.matterbridgeInformation.loggerLevel === "info" || this.matterbridge.matterbridgeInformation.matterLoggerLevel === MatterLogLevel.INFO)
142
+ callbackLogLevel = "info";
143
+ if (this.matterbridge.matterbridgeInformation.loggerLevel === "debug" || this.matterbridge.matterbridgeInformation.matterLoggerLevel === MatterLogLevel.DEBUG)
144
+ callbackLogLevel = "debug";
238
145
  AnsiLogger.setGlobalCallback(this.wssSendMessage.bind(this), callbackLogLevel);
239
146
  this.log.debug(`WebSocketServer logger global callback set to ${callbackLogLevel}`);
240
147
  this.log.info(`WebSocketServer client "${clientIp}" connected to Matterbridge`);
@@ -268,7 +175,6 @@ export class Frontend {
268
175
  this.webSocketServer.on('error', (ws, error) => {
269
176
  this.log.error(`WebSocketServer error: ${error}`);
270
177
  });
271
- // Subscribe to cli events
272
178
  const { cliEmitter } = await import('./cli.js');
273
179
  cliEmitter.on('uptime', (systemUptime, processUptime) => {
274
180
  this.wssSendUptimeUpdate(systemUptime, processUptime);
@@ -279,7 +185,6 @@ export class Frontend {
279
185
  cliEmitter.on('cpu', (cpuUsage) => {
280
186
  this.wssSendCpuUpdate(cpuUsage);
281
187
  });
282
- // Endpoint to validate login code
283
188
  this.expressApp.post('/api/login', express.json(), async (req, res) => {
284
189
  const { password } = req.body;
285
190
  this.log.debug('The frontend sent /api/login', password);
@@ -298,27 +203,23 @@ export class Frontend {
298
203
  this.log.warn('/api/login error wrong password');
299
204
  res.json({ valid: false });
300
205
  }
301
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
302
206
  }
303
207
  catch (error) {
304
208
  this.log.error('/api/login error getting password');
305
209
  res.json({ valid: false });
306
210
  }
307
211
  });
308
- // Endpoint to provide health check
309
212
  this.expressApp.get('/health', (req, res) => {
310
213
  this.log.debug('Express received /health');
311
214
  const healthStatus = {
312
- status: 'ok', // Indicate service is healthy
313
- uptime: process.uptime(), // Server uptime in seconds
314
- timestamp: new Date().toISOString(), // Current timestamp
215
+ status: 'ok',
216
+ uptime: process.uptime(),
217
+ timestamp: new Date().toISOString(),
315
218
  };
316
219
  res.status(200).json(healthStatus);
317
220
  });
318
- // Endpoint to provide memory usage details
319
221
  this.expressApp.get('/memory', async (req, res) => {
320
222
  this.log.debug('Express received /memory');
321
- // Memory usage from process
322
223
  const memoryUsageRaw = process.memoryUsage();
323
224
  const memoryUsage = {
324
225
  rss: this.formatMemoryUsage(memoryUsageRaw.rss),
@@ -327,13 +228,10 @@ export class Frontend {
327
228
  external: this.formatMemoryUsage(memoryUsageRaw.external),
328
229
  arrayBuffers: this.formatMemoryUsage(memoryUsageRaw.arrayBuffers),
329
230
  };
330
- // V8 heap statistics
331
231
  const { default: v8 } = await import('node:v8');
332
232
  const heapStatsRaw = v8.getHeapStatistics();
333
233
  const heapSpacesRaw = v8.getHeapSpaceStatistics();
334
- // Format heapStats
335
234
  const heapStats = Object.fromEntries(Object.entries(heapStatsRaw).map(([key, value]) => [key, this.formatMemoryUsage(value)]));
336
- // Format heapSpaces
337
235
  const heapSpaces = heapSpacesRaw.map((space) => ({
338
236
  ...space,
339
237
  space_size: this.formatMemoryUsage(space.space_size),
@@ -351,7 +249,6 @@ export class Frontend {
351
249
  };
352
250
  res.status(200).json(memoryReport);
353
251
  });
354
- // Endpoint to start advertising the server node
355
252
  this.expressApp.get('/api/advertise', express.json(), async (req, res) => {
356
253
  const pairingCodes = await this.matterbridge.advertiseServerNode(this.matterbridge.serverNode);
357
254
  if (pairingCodes) {
@@ -362,22 +259,18 @@ export class Frontend {
362
259
  res.status(500).json({ error: 'Failed to generate pairing codes' });
363
260
  }
364
261
  });
365
- // Endpoint to provide settings
366
262
  this.expressApp.get('/api/settings', express.json(), async (req, res) => {
367
263
  this.log.debug('The frontend sent /api/settings');
368
264
  res.json(await this.getApiSettings());
369
265
  });
370
- // Endpoint to provide plugins
371
266
  this.expressApp.get('/api/plugins', async (req, res) => {
372
267
  this.log.debug('The frontend sent /api/plugins');
373
268
  res.json(this.getBaseRegisteredPlugins());
374
269
  });
375
- // Endpoint to provide devices
376
270
  this.expressApp.get('/api/devices', (req, res) => {
377
271
  this.log.debug('The frontend sent /api/devices');
378
272
  const devices = [];
379
273
  this.matterbridge.devices.forEach(async (device) => {
380
- // Check if the device has the required properties
381
274
  if (!device.plugin || !device.name || !device.deviceName || !device.serialNumber || !device.uniqueId || !device.lifecycle.isReady)
382
275
  return;
383
276
  const cluster = this.getClusterTextFromDevice(device);
@@ -395,7 +288,6 @@ export class Frontend {
395
288
  });
396
289
  res.json(devices);
397
290
  });
398
- // Endpoint to provide the cluster servers of the devices
399
291
  this.expressApp.get('/api/devices_clusters/:selectedPluginName/:selectedDeviceEndpoint', (req, res) => {
400
292
  const selectedPluginName = req.params.selectedPluginName;
401
293
  const selectedDeviceEndpoint = parseInt(req.params.selectedDeviceEndpoint, 10);
@@ -468,7 +360,6 @@ export class Frontend {
468
360
  });
469
361
  res.json(data);
470
362
  });
471
- // Endpoint to view the log
472
363
  this.expressApp.get('/api/view-log', async (req, res) => {
473
364
  this.log.debug('The frontend sent /api/log');
474
365
  try {
@@ -481,12 +372,10 @@ export class Frontend {
481
372
  res.status(500).send('Error reading log file');
482
373
  }
483
374
  });
484
- // Endpoint to download the matterbridge log
485
375
  this.expressApp.get('/api/download-mblog', async (req, res) => {
486
376
  this.log.debug('The frontend sent /api/download-mblog');
487
377
  try {
488
378
  await fs.access(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterbrideLoggerFile), fs.constants.F_OK);
489
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
490
379
  }
491
380
  catch (error) {
492
381
  fs.appendFile(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterbrideLoggerFile), 'Enable the log on file in the settings to enable the file logger');
@@ -498,12 +387,10 @@ export class Frontend {
498
387
  }
499
388
  });
500
389
  });
501
- // Endpoint to download the matter log
502
390
  this.expressApp.get('/api/download-mjlog', async (req, res) => {
503
391
  this.log.debug('The frontend sent /api/download-mjlog');
504
392
  try {
505
393
  await fs.access(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterLoggerFile), fs.constants.F_OK);
506
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
507
394
  }
508
395
  catch (error) {
509
396
  fs.appendFile(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterLoggerFile), 'Enable the log on file in the settings to enable the file logger');
@@ -515,7 +402,21 @@ export class Frontend {
515
402
  }
516
403
  });
517
404
  });
518
- // Endpoint to download the matter storage file
405
+ this.expressApp.get('/api/shellydownloadsystemlog', async (req, res) => {
406
+ this.log.debug('The frontend sent /api/shellydownloadsystemlog');
407
+ try {
408
+ await fs.access(path.join(this.matterbridge.matterbridgeDirectory, 'shelly.log'), fs.constants.F_OK);
409
+ }
410
+ catch (error) {
411
+ fs.appendFile(path.join(this.matterbridge.matterbridgeDirectory, 'shelly.log'), 'Create the Shelly system log before downloading it.');
412
+ }
413
+ res.download(path.join(this.matterbridge.matterbridgeDirectory, 'shelly.log'), 'shelly.log', (error) => {
414
+ if (error) {
415
+ this.log.error(`Error downloading Shelly system log file: ${error instanceof Error ? error.message : error}`);
416
+ res.status(500).send('Error downloading Shelly system log file');
417
+ }
418
+ });
419
+ });
519
420
  this.expressApp.get('/api/download-mjstorage', async (req, res) => {
520
421
  this.log.debug('The frontend sent /api/download-mjstorage');
521
422
  await createZip(path.join(os.tmpdir(), `matterbridge.${this.matterbridge.matterStorageName}.zip`), path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterStorageName));
@@ -526,7 +427,6 @@ export class Frontend {
526
427
  }
527
428
  });
528
429
  });
529
- // Endpoint to download the matterbridge storage directory
530
430
  this.expressApp.get('/api/download-mbstorage', async (req, res) => {
531
431
  this.log.debug('The frontend sent /api/download-mbstorage');
532
432
  await createZip(path.join(os.tmpdir(), `matterbridge.${this.matterbridge.nodeStorageName}.zip`), path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.nodeStorageName));
@@ -537,7 +437,6 @@ export class Frontend {
537
437
  }
538
438
  });
539
439
  });
540
- // Endpoint to download the matterbridge plugin directory
541
440
  this.expressApp.get('/api/download-pluginstorage', async (req, res) => {
542
441
  this.log.debug('The frontend sent /api/download-pluginstorage');
543
442
  await createZip(path.join(os.tmpdir(), `matterbridge.pluginstorage.zip`), this.matterbridge.matterbridgePluginDirectory);
@@ -548,11 +447,9 @@ export class Frontend {
548
447
  }
549
448
  });
550
449
  });
551
- // Endpoint to download the matterbridge plugin config files
552
450
  this.expressApp.get('/api/download-pluginconfig', async (req, res) => {
553
451
  this.log.debug('The frontend sent /api/download-pluginconfig');
554
452
  await createZip(path.join(os.tmpdir(), `matterbridge.pluginconfig.zip`), path.relative(process.cwd(), path.join(this.matterbridge.matterbridgeDirectory, '*.config.json')));
555
- // 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')));
556
453
  res.download(path.join(os.tmpdir(), `matterbridge.pluginconfig.zip`), `matterbridge.pluginconfig.zip`, (error) => {
557
454
  if (error) {
558
455
  this.log.error(`Error downloading file matterbridge.pluginstorage.zip: ${error instanceof Error ? error.message : error}`);
@@ -560,7 +457,6 @@ export class Frontend {
560
457
  }
561
458
  });
562
459
  });
563
- // Endpoint to download the matterbridge plugin config files
564
460
  this.expressApp.get('/api/download-backup', async (req, res) => {
565
461
  this.log.debug('The frontend sent /api/download-backup');
566
462
  res.download(path.join(os.tmpdir(), `matterbridge.backup.zip`), `matterbridge.backup.zip`, (error) => {
@@ -570,7 +466,6 @@ export class Frontend {
570
466
  }
571
467
  });
572
468
  });
573
- // Endpoint to receive commands
574
469
  this.expressApp.post('/api/command/:command/:param', express.json(), async (req, res) => {
575
470
  const command = req.params.command;
576
471
  let param = req.params.param;
@@ -580,15 +475,13 @@ export class Frontend {
580
475
  return;
581
476
  }
582
477
  this.log.debug(`Received frontend command: ${command}:${param}`);
583
- // Handle the command setpassword from Settings
584
478
  if (command === 'setpassword') {
585
- const password = param.slice(1, -1); // Remove the first and last characters
479
+ const password = param.slice(1, -1);
586
480
  this.log.debug('setpassword', param, password);
587
481
  await this.matterbridge.nodeContext?.set('password', password);
588
482
  res.json({ message: 'Command received' });
589
483
  return;
590
484
  }
591
- // Handle the command setbridgemode from Settings
592
485
  if (command === 'setbridgemode') {
593
486
  this.log.debug(`setbridgemode: ${param}`);
594
487
  this.wssSendRestartRequired();
@@ -596,7 +489,6 @@ export class Frontend {
596
489
  res.json({ message: 'Command received' });
597
490
  return;
598
491
  }
599
- // Handle the command backup from Settings
600
492
  if (command === 'backup') {
601
493
  this.log.notice(`Prepairing the backup...`);
602
494
  await createZip(path.join(os.tmpdir(), `matterbridge.backup.zip`), path.join(this.matterbridge.matterbridgeDirectory), path.join(this.matterbridge.matterbridgePluginDirectory));
@@ -605,33 +497,31 @@ export class Frontend {
605
497
  res.json({ message: 'Command received' });
606
498
  return;
607
499
  }
608
- // Handle the command setmbloglevel from Settings
609
500
  if (command === 'setmbloglevel') {
610
501
  this.log.debug('Matterbridge log level:', param);
611
502
  if (param === 'Debug') {
612
- this.log.logLevel = "debug" /* LogLevel.DEBUG */;
503
+ this.log.logLevel = "debug";
613
504
  }
614
505
  else if (param === 'Info') {
615
- this.log.logLevel = "info" /* LogLevel.INFO */;
506
+ this.log.logLevel = "info";
616
507
  }
617
508
  else if (param === 'Notice') {
618
- this.log.logLevel = "notice" /* LogLevel.NOTICE */;
509
+ this.log.logLevel = "notice";
619
510
  }
620
511
  else if (param === 'Warn') {
621
- this.log.logLevel = "warn" /* LogLevel.WARN */;
512
+ this.log.logLevel = "warn";
622
513
  }
623
514
  else if (param === 'Error') {
624
- this.log.logLevel = "error" /* LogLevel.ERROR */;
515
+ this.log.logLevel = "error";
625
516
  }
626
517
  else if (param === 'Fatal') {
627
- this.log.logLevel = "fatal" /* LogLevel.FATAL */;
518
+ this.log.logLevel = "fatal";
628
519
  }
629
520
  await this.matterbridge.nodeContext?.set('matterbridgeLogLevel', this.log.logLevel);
630
521
  await this.matterbridge.setLogLevel(this.log.logLevel);
631
522
  res.json({ message: 'Command received' });
632
523
  return;
633
524
  }
634
- // Handle the command setmbloglevel from Settings
635
525
  if (command === 'setmjloglevel') {
636
526
  this.log.debug('Matter.js log level:', param);
637
527
  if (param === 'Debug') {
@@ -656,34 +546,30 @@ export class Frontend {
656
546
  res.json({ message: 'Command received' });
657
547
  return;
658
548
  }
659
- // Handle the command setmdnsinterface from Settings
660
549
  if (command === 'setmdnsinterface') {
661
- param = param.slice(1, -1); // Remove the first and last characters *mdns*
550
+ param = param.slice(1, -1);
662
551
  this.matterbridge.matterbridgeInformation.mattermdnsinterface = param;
663
552
  this.log.debug('Matter.js mdns interface:', param === '' ? 'All interfaces' : param);
664
553
  await this.matterbridge.nodeContext?.set('mattermdnsinterface', param);
665
554
  res.json({ message: 'Command received' });
666
555
  return;
667
556
  }
668
- // Handle the command setipv4address from Settings
669
557
  if (command === 'setipv4address') {
670
- param = param.slice(1, -1); // Remove the first and last characters *ip*
558
+ param = param.slice(1, -1);
671
559
  this.matterbridge.matterbridgeInformation.matteripv4address = param;
672
560
  this.log.debug('Matter.js ipv4 address:', param === '' ? 'All ipv4 addresses' : param);
673
561
  await this.matterbridge.nodeContext?.set('matteripv4address', param);
674
562
  res.json({ message: 'Command received' });
675
563
  return;
676
564
  }
677
- // Handle the command setipv6address from Settings
678
565
  if (command === 'setipv6address') {
679
- param = param.slice(1, -1); // Remove the first and last characters *ip*
566
+ param = param.slice(1, -1);
680
567
  this.matterbridge.matterbridgeInformation.matteripv6address = param;
681
568
  this.log.debug('Matter.js ipv6 address:', param === '' ? 'All ipv6 addresses' : param);
682
569
  await this.matterbridge.nodeContext?.set('matteripv6address', param);
683
570
  res.json({ message: 'Command received' });
684
571
  return;
685
572
  }
686
- // Handle the command setmatterport from Settings
687
573
  if (command === 'setmatterport') {
688
574
  const port = Math.min(Math.max(parseInt(param), 5540), 5560);
689
575
  this.matterbridge.matterbridgeInformation.matterPort = port;
@@ -692,7 +578,6 @@ export class Frontend {
692
578
  res.json({ message: 'Command received' });
693
579
  return;
694
580
  }
695
- // Handle the command setmatterdiscriminator from Settings
696
581
  if (command === 'setmatterdiscriminator') {
697
582
  const discriminator = Math.min(Math.max(parseInt(param), 1000), 4095);
698
583
  this.matterbridge.matterbridgeInformation.matterDiscriminator = discriminator;
@@ -701,7 +586,6 @@ export class Frontend {
701
586
  res.json({ message: 'Command received' });
702
587
  return;
703
588
  }
704
- // Handle the command setmatterpasscode from Settings
705
589
  if (command === 'setmatterpasscode') {
706
590
  const passcode = Math.min(Math.max(parseInt(param), 10000000), 90000000);
707
591
  this.matterbridge.matterbridgeInformation.matterPasscode = passcode;
@@ -710,20 +594,17 @@ export class Frontend {
710
594
  res.json({ message: 'Command received' });
711
595
  return;
712
596
  }
713
- // Handle the command setmbloglevel from Settings
714
597
  if (command === 'setmblogfile') {
715
598
  this.log.debug('Matterbridge file log:', param);
716
599
  this.matterbridge.matterbridgeInformation.fileLogger = param === 'true';
717
600
  await this.matterbridge.nodeContext?.set('matterbridgeFileLog', param === 'true');
718
- // Create the file logger for matterbridge
719
601
  if (param === 'true')
720
- AnsiLogger.setGlobalLogfile(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterbrideLoggerFile), "debug" /* LogLevel.DEBUG */, true);
602
+ AnsiLogger.setGlobalLogfile(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterbrideLoggerFile), "debug", true);
721
603
  else
722
604
  AnsiLogger.setGlobalLogfile(undefined);
723
605
  res.json({ message: 'Command received' });
724
606
  return;
725
607
  }
726
- // Handle the command setmbloglevel from Settings
727
608
  if (command === 'setmjlogfile') {
728
609
  this.log.debug('Matter file log:', param);
729
610
  this.matterbridge.matterbridgeInformation.matterFileLogger = param === 'true';
@@ -750,48 +631,40 @@ export class Frontend {
750
631
  res.json({ message: 'Command received' });
751
632
  return;
752
633
  }
753
- // Handle the command unregister from Settings
754
634
  if (command === 'unregister') {
755
635
  await this.matterbridge.unregisterAndShutdownProcess();
756
636
  res.json({ message: 'Command received' });
757
637
  return;
758
638
  }
759
- // Handle the command reset from Settings
760
639
  if (command === 'reset') {
761
640
  await this.matterbridge.shutdownProcessAndReset();
762
641
  res.json({ message: 'Command received' });
763
642
  return;
764
643
  }
765
- // Handle the command factoryreset from Settings
766
644
  if (command === 'factoryreset') {
767
645
  await this.matterbridge.shutdownProcessAndFactoryReset();
768
646
  res.json({ message: 'Command received' });
769
647
  return;
770
648
  }
771
- // Handle the command shutdown from Header
772
649
  if (command === 'shutdown') {
773
650
  await this.matterbridge.shutdownProcess();
774
651
  res.json({ message: 'Command received' });
775
652
  return;
776
653
  }
777
- // Handle the command restart from Header
778
654
  if (command === 'restart') {
779
655
  await this.matterbridge.restartProcess();
780
656
  res.json({ message: 'Command received' });
781
657
  return;
782
658
  }
783
- // Handle the command update from Header
784
659
  if (command === 'update') {
785
660
  await this.matterbridge.updateProcess();
786
661
  this.wssSendRestartRequired();
787
662
  res.json({ message: 'Command received' });
788
663
  return;
789
664
  }
790
- // Handle the command saveconfig from Home
791
665
  if (command === 'saveconfig') {
792
666
  param = param.replace(/\*/g, '\\');
793
667
  this.log.info(`Saving config for plugin ${plg}${param}${nf}...`);
794
- // console.log('Req.body:', JSON.stringify(req.body, null, 2));
795
668
  if (!this.matterbridge.plugins.has(param)) {
796
669
  this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
797
670
  }
@@ -806,7 +679,6 @@ export class Frontend {
806
679
  res.json({ message: 'Command received' });
807
680
  return;
808
681
  }
809
- // Handle the command installplugin from Home
810
682
  if (command === 'installplugin') {
811
683
  param = param.replace(/\*/g, '\\');
812
684
  this.log.info(`Installing plugin ${plg}${param}${nf}...`);
@@ -815,7 +687,6 @@ export class Frontend {
815
687
  await this.matterbridge.spawnCommand('npm', ['install', '-g', param, '--omit=dev', '--verbose']);
816
688
  this.log.info(`Plugin ${plg}${param}${nf} installed. Full restart required.`);
817
689
  this.wssSendSnackbarMessage(`Installed package ${param}`);
818
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
819
690
  }
820
691
  catch (error) {
821
692
  this.log.error(`Error installing plugin ${plg}${param}${er}`);
@@ -824,21 +695,16 @@ export class Frontend {
824
695
  this.wssSendSnackbarMessage(`Restart required`, 0);
825
696
  this.wssSendRestartRequired();
826
697
  param = param.split('@')[0];
827
- // Also add the plugin to matterbridge so no return!
828
698
  if (param === 'matterbridge') {
829
- // 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
830
699
  res.json({ message: 'Command received' });
831
700
  return;
832
701
  }
833
702
  }
834
- // Handle the command addplugin from Home
835
703
  if (command === 'addplugin' || command === 'installplugin') {
836
704
  param = param.replace(/\*/g, '\\');
837
705
  const plugin = await this.matterbridge.plugins.add(param);
838
706
  if (plugin) {
839
707
  if (this.matterbridge.bridgeMode === 'childbridge') {
840
- // 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
841
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
842
708
  this.matterbridge.createDynamicPlugin(plugin, true);
843
709
  }
844
710
  this.matterbridge.plugins.load(plugin, true, 'The plugin has been added', true).then(() => {
@@ -848,21 +714,19 @@ export class Frontend {
848
714
  res.json({ message: 'Command received' });
849
715
  return;
850
716
  }
851
- // Handle the command removeplugin from Home
852
717
  if (command === 'removeplugin') {
853
718
  if (!this.matterbridge.plugins.has(param)) {
854
719
  this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
855
720
  }
856
721
  else {
857
722
  const plugin = this.matterbridge.plugins.get(param);
858
- await this.matterbridge.plugins.shutdown(plugin, 'The plugin has been removed.', true); // This will also close the server node in childbridge mode
723
+ await this.matterbridge.plugins.shutdown(plugin, 'The plugin has been removed.', true);
859
724
  await this.matterbridge.plugins.remove(param);
860
725
  }
861
726
  res.json({ message: 'Command received' });
862
727
  this.wssSendRefreshRequired();
863
728
  return;
864
729
  }
865
- // Handle the command enableplugin from Home
866
730
  if (command === 'enableplugin') {
867
731
  if (!this.matterbridge.plugins.has(param)) {
868
732
  this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
@@ -880,7 +744,6 @@ export class Frontend {
880
744
  plugin.addedDevices = undefined;
881
745
  await this.matterbridge.plugins.enable(param);
882
746
  if (this.matterbridge.bridgeMode === 'childbridge' && plugin.type === 'DynamicPlatform') {
883
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
884
747
  this.matterbridge.createDynamicPlugin(plugin, true);
885
748
  }
886
749
  this.matterbridge.plugins.load(plugin, true, 'The plugin has been enabled', true).then(() => {
@@ -892,7 +755,6 @@ export class Frontend {
892
755
  this.wssSendRefreshRequired();
893
756
  return;
894
757
  }
895
- // Handle the command disableplugin from Home
896
758
  if (command === 'disableplugin') {
897
759
  if (!this.matterbridge.plugins.has(param)) {
898
760
  this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
@@ -900,7 +762,7 @@ export class Frontend {
900
762
  else {
901
763
  const plugin = this.matterbridge.plugins.get(param);
902
764
  if (plugin && plugin.enabled) {
903
- await this.matterbridge.plugins.shutdown(plugin, 'The plugin has been disabled.', true); // This will also close the server node in childbridge mode
765
+ await this.matterbridge.plugins.shutdown(plugin, 'The plugin has been disabled.', true);
904
766
  await this.matterbridge.plugins.disable(param);
905
767
  }
906
768
  }
@@ -909,7 +771,6 @@ export class Frontend {
909
771
  return;
910
772
  }
911
773
  });
912
- // Fallback for routing (must be the last route)
913
774
  this.expressApp.get('*', (req, res) => {
914
775
  this.log.debug('The frontend sent:', req.url);
915
776
  this.log.debug('Response send file:', path.join(this.matterbridge.rootDirectory, 'frontend/build/index.html'));
@@ -918,29 +779,24 @@ export class Frontend {
918
779
  this.log.debug(`Frontend initialized on port ${YELLOW}${this.port}${db} static ${UNDERLINE}${path.join(this.matterbridge.rootDirectory, 'frontend/build')}${UNDERLINEOFF}${rs}`);
919
780
  }
920
781
  async stop() {
921
- // Close the http server
922
782
  if (this.httpServer) {
923
783
  this.httpServer.close();
924
784
  this.httpServer.removeAllListeners();
925
785
  this.httpServer = undefined;
926
786
  this.log.debug('Frontend http server closed successfully');
927
787
  }
928
- // Close the https server
929
788
  if (this.httpsServer) {
930
789
  this.httpsServer.close();
931
790
  this.httpsServer.removeAllListeners();
932
791
  this.httpsServer = undefined;
933
792
  this.log.debug('Frontend https server closed successfully');
934
793
  }
935
- // Remove listeners from the express app
936
794
  if (this.expressApp) {
937
795
  this.expressApp.removeAllListeners();
938
796
  this.expressApp = undefined;
939
797
  this.log.debug('Frontend app closed successfully');
940
798
  }
941
- // Close the WebSocket server
942
799
  if (this.webSocketServer) {
943
- // Close all active connections
944
800
  this.webSocketServer.clients.forEach((client) => {
945
801
  if (client.readyState === WebSocket.OPEN) {
946
802
  client.close();
@@ -957,7 +813,6 @@ export class Frontend {
957
813
  this.webSocketServer = undefined;
958
814
  }
959
815
  }
960
- // Function to format bytes to KB, MB, or GB
961
816
  formatMemoryUsage = (bytes) => {
962
817
  if (bytes >= 1024 ** 3) {
963
818
  return `${(bytes / 1024 ** 3).toFixed(2)} GB`;
@@ -969,7 +824,6 @@ export class Frontend {
969
824
  return `${(bytes / 1024).toFixed(2)} KB`;
970
825
  }
971
826
  };
972
- // Function to format system uptime with only the most significant unit
973
827
  formatOsUpTime = (seconds) => {
974
828
  if (seconds >= 86400) {
975
829
  const days = Math.floor(seconds / 86400);
@@ -985,13 +839,8 @@ export class Frontend {
985
839
  }
986
840
  return `${seconds} second${seconds !== 1 ? 's' : ''}`;
987
841
  };
988
- /**
989
- * Retrieves the api settings data.
990
- * @returns {Promise<object>} A promise that resolve in the api settings object.
991
- */
992
842
  async getApiSettings() {
993
843
  const { lastCpuUsage } = await import('./cli.js');
994
- // Update the system information
995
844
  this.matterbridge.systemInformation.totalMemory = this.formatMemoryUsage(os.totalmem());
996
845
  this.matterbridge.systemInformation.freeMemory = this.formatMemoryUsage(os.freemem());
997
846
  this.matterbridge.systemInformation.systemUptime = this.formatOsUpTime(os.uptime());
@@ -1000,7 +849,6 @@ export class Frontend {
1000
849
  this.matterbridge.systemInformation.rss = this.formatMemoryUsage(process.memoryUsage().rss);
1001
850
  this.matterbridge.systemInformation.heapTotal = this.formatMemoryUsage(process.memoryUsage().heapTotal);
1002
851
  this.matterbridge.systemInformation.heapUsed = this.formatMemoryUsage(process.memoryUsage().heapUsed);
1003
- // Update the matterbridge information
1004
852
  this.matterbridge.matterbridgeInformation.bridgeMode = this.matterbridge.bridgeMode;
1005
853
  this.matterbridge.matterbridgeInformation.restartMode = this.matterbridge.restartMode;
1006
854
  this.matterbridge.matterbridgeInformation.loggerLevel = this.matterbridge.log.logLevel;
@@ -1019,11 +867,6 @@ export class Frontend {
1019
867
  this.matterbridge.matterbridgeInformation.profile = this.matterbridge.profile;
1020
868
  return { systemInformation: this.matterbridge.systemInformation, matterbridgeInformation: this.matterbridge.matterbridgeInformation };
1021
869
  }
1022
- /**
1023
- * Retrieves the cluster text description from a given device.
1024
- * @param {MatterbridgeDevice} device - The MatterbridgeDevice object.
1025
- * @returns {string} The attributes description of the cluster servers in the device.
1026
- */
1027
870
  getClusterTextFromDevice(device) {
1028
871
  const getAttribute = (device, cluster, attribute) => {
1029
872
  let value = undefined;
@@ -1062,7 +905,6 @@ export class Frontend {
1062
905
  };
1063
906
  let attributes = '';
1064
907
  device.forEachAttribute((clusterName, clusterId, attributeName, attributeId, attributeValue) => {
1065
- // console.log(`${device.deviceName} => Cluster: ${clusterName}-${clusterId} Attribute: ${attributeName}-${attributeId} Value(${typeof attributeValue}): ${attributeValue}`);
1066
908
  if (typeof attributeValue === 'undefined')
1067
909
  return;
1068
910
  if (clusterName === 'onOff' && attributeName === 'onOff')
@@ -1140,13 +982,8 @@ export class Frontend {
1140
982
  if (clusterName === 'userLabel' && attributeName === 'labelList')
1141
983
  attributes += `${getUserLabel(device)} `;
1142
984
  });
1143
- // console.log(`${device.deviceName}.forEachAttribute: ${attributes}`);
1144
985
  return attributes.trimStart().trimEnd();
1145
986
  }
1146
- /**
1147
- * Retrieves the base registered plugins sanitized for res.json().
1148
- * @returns {BaseRegisteredPlugin[]} An array of BaseRegisteredPlugin.
1149
- */
1150
987
  getBaseRegisteredPlugins() {
1151
988
  const baseRegisteredPlugins = [];
1152
989
  for (const plugin of this.matterbridge.plugins) {
@@ -1177,13 +1014,6 @@ export class Frontend {
1177
1014
  }
1178
1015
  return baseRegisteredPlugins;
1179
1016
  }
1180
- /**
1181
- * Handles incoming websocket messages for the Matterbridge frontend.
1182
- *
1183
- * @param {WebSocket} client - The websocket client that sent the message.
1184
- * @param {WebSocket.RawData} message - The raw data of the message received from the client.
1185
- * @returns {Promise<void>} A promise that resolves when the message has been handled.
1186
- */
1187
1017
  async wsMessageHandler(client, message) {
1188
1018
  let data;
1189
1019
  try {
@@ -1273,6 +1103,11 @@ export class Frontend {
1273
1103
  triggerShellyMainUpdate(this.matterbridge);
1274
1104
  return;
1275
1105
  }
1106
+ else if (data.method === '/api/shellycreatesystemlog') {
1107
+ const { createShellySystemLog } = await import('./shelly.js');
1108
+ createShellySystemLog(this.matterbridge);
1109
+ return;
1110
+ }
1276
1111
  else if (data.method === '/api/shellynetconfig') {
1277
1112
  this.log.debug('/api/shellynetconfig:', data.params);
1278
1113
  const { triggerShellyChangeIp: triggerShellyChangeNet } = await import('./shelly.js');
@@ -1324,10 +1159,8 @@ export class Frontend {
1324
1159
  else if (data.method === '/api/devices') {
1325
1160
  const devices = [];
1326
1161
  this.matterbridge.devices.forEach(async (device) => {
1327
- // Filter by pluginName if provided
1328
1162
  if (data.params.pluginName && data.params.pluginName !== device.plugin)
1329
1163
  return;
1330
- // Check if the device has the required properties
1331
1164
  if (!device.plugin || !device.name || !device.deviceName || !device.serialNumber || !device.uniqueId || !device.lifecycle.isReady)
1332
1165
  return;
1333
1166
  const cluster = this.getClusterTextFromDevice(device);
@@ -1410,7 +1243,6 @@ export class Frontend {
1410
1243
  });
1411
1244
  endpointServer.getChildEndpoints().forEach((childEndpoint) => {
1412
1245
  deviceTypes = [];
1413
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1414
1246
  const name = childEndpoint.endpoint?.id;
1415
1247
  const clusterServers = childEndpoint.getAllClusterServers();
1416
1248
  clusterServers.forEach((clusterServer) => {
@@ -1493,139 +1325,85 @@ export class Frontend {
1493
1325
  return;
1494
1326
  }
1495
1327
  }
1496
- /**
1497
- * Sends a WebSocket message to all connected clients. The function is called by AnsiLogger.setGlobalCallback.
1498
- *
1499
- * @param {string} level - The logger level of the message: debug info notice warn error fatal...
1500
- * @param {string} time - The time string of the message
1501
- * @param {string} name - The logger name of the message
1502
- * @param {string} message - The content of the message.
1503
- */
1504
1328
  wssSendMessage(level, time, name, message) {
1505
1329
  if (!level || !time || !name || !message)
1506
1330
  return;
1507
- // Remove ANSI escape codes from the message
1508
- // eslint-disable-next-line no-control-regex
1509
1331
  message = message.replace(/\x1B\[[0-9;]*[m|s|u|K]/g, '');
1510
- // Remove leading asterisks from the message
1511
1332
  message = message.replace(/^\*+/, '');
1512
- // Replace all occurrences of \t and \n
1513
1333
  message = message.replace(/[\t\n]/g, '');
1514
- // Remove non-printable characters
1515
- // eslint-disable-next-line no-control-regex
1516
1334
  message = message.replace(/[\x00-\x1F\x7F]/g, '');
1517
- // Replace all occurrences of \" with "
1518
1335
  message = message.replace(/\\"/g, '"');
1519
- // Define the maximum allowed length for continuous characters without a space
1520
1336
  const maxContinuousLength = 100;
1521
1337
  const keepStartLength = 20;
1522
1338
  const keepEndLength = 20;
1523
- // Split the message into words
1524
1339
  message = message
1525
1340
  .split(' ')
1526
1341
  .map((word) => {
1527
- // If the word length exceeds the max continuous length, insert spaces and truncate
1528
1342
  if (word.length > maxContinuousLength) {
1529
1343
  return word.slice(0, keepStartLength) + ' ... ' + word.slice(-keepEndLength);
1530
1344
  }
1531
1345
  return word;
1532
1346
  })
1533
1347
  .join(' ');
1534
- // Send the message to all connected clients
1535
1348
  this.webSocketServer?.clients.forEach((client) => {
1536
1349
  if (client.readyState === WebSocket.OPEN) {
1537
1350
  client.send(JSON.stringify({ id: WS_ID_LOG, src: 'Matterbridge', level, time, name, message }));
1538
1351
  }
1539
1352
  });
1540
1353
  }
1541
- /**
1542
- * Sends a need to refresh WebSocket message to all connected clients.
1543
- *
1544
- */
1545
1354
  wssSendRefreshRequired() {
1546
1355
  this.log.debug('Sending a refresh required message to all connected clients');
1547
1356
  this.matterbridge.matterbridgeInformation.refreshRequired = true;
1548
- // Send the message to all connected clients
1549
1357
  this.webSocketServer?.clients.forEach((client) => {
1550
1358
  if (client.readyState === WebSocket.OPEN) {
1551
1359
  client.send(JSON.stringify({ id: WS_ID_REFRESH_NEEDED, src: 'Matterbridge', dst: 'Frontend', method: 'refresh_required', params: {} }));
1552
1360
  }
1553
1361
  });
1554
1362
  }
1555
- /**
1556
- * Sends a need to restart WebSocket message to all connected clients.
1557
- *
1558
- */
1559
1363
  wssSendRestartRequired() {
1560
1364
  this.log.debug('Sending a restart required message to all connected clients');
1561
1365
  this.matterbridge.matterbridgeInformation.restartRequired = true;
1562
1366
  this.wssSendSnackbarMessage(`Restart required`, 0);
1563
- // Send the message to all connected clients
1564
1367
  this.webSocketServer?.clients.forEach((client) => {
1565
1368
  if (client.readyState === WebSocket.OPEN) {
1566
1369
  client.send(JSON.stringify({ id: WS_ID_RESTART_NEEDED, src: 'Matterbridge', dst: 'Frontend', method: 'restart_required', params: {} }));
1567
1370
  }
1568
1371
  });
1569
1372
  }
1570
- /**
1571
- * Sends a memory update message to all connected clients.
1572
- *
1573
- */
1574
1373
  wssSendCpuUpdate(cpuUsage) {
1575
1374
  this.log.debug('Sending a cpu update message to all connected clients');
1576
- // Send the message to all connected clients
1577
1375
  this.webSocketServer?.clients.forEach((client) => {
1578
1376
  if (client.readyState === WebSocket.OPEN) {
1579
1377
  client.send(JSON.stringify({ id: WS_ID_CPU_UPDATE, src: 'Matterbridge', dst: 'Frontend', method: 'cpu_update', params: { cpuUsage } }));
1580
1378
  }
1581
1379
  });
1582
1380
  }
1583
- /**
1584
- * Sends a cpu update message to all connected clients.
1585
- *
1586
- */
1587
1381
  wssSendMemoryUpdate(totalMemory, freeMemory, rss, heapTotal, heapUsed, external, arrayBuffers) {
1588
1382
  this.log.debug('Sending a memory update message to all connected clients');
1589
- // Send the message to all connected clients
1590
1383
  this.webSocketServer?.clients.forEach((client) => {
1591
1384
  if (client.readyState === WebSocket.OPEN) {
1592
1385
  client.send(JSON.stringify({ id: WS_ID_MEMORY_UPDATE, src: 'Matterbridge', dst: 'Frontend', method: 'memory_update', params: { totalMemory, freeMemory, rss, heapTotal, heapUsed, external, arrayBuffers } }));
1593
1386
  }
1594
1387
  });
1595
1388
  }
1596
- /**
1597
- * Sends a memory update message to all connected clients.
1598
- *
1599
- */
1600
1389
  wssSendUptimeUpdate(systemUptime, processUptime) {
1601
1390
  this.log.debug('Sending a uptime update message to all connected clients');
1602
- // Send the message to all connected clients
1603
1391
  this.webSocketServer?.clients.forEach((client) => {
1604
1392
  if (client.readyState === WebSocket.OPEN) {
1605
1393
  client.send(JSON.stringify({ id: WS_ID_UPTIME_UPDATE, src: 'Matterbridge', dst: 'Frontend', method: 'uptime_update', params: { systemUptime, processUptime } }));
1606
1394
  }
1607
1395
  });
1608
1396
  }
1609
- /**
1610
- * Sends a cpu update message to all connected clients.
1611
- *
1612
- */
1613
1397
  wssSendSnackbarMessage(message, timeout = 5) {
1614
1398
  this.log.debug('Sending a snackbar message to all connected clients');
1615
- // Send the message to all connected clients
1616
1399
  this.webSocketServer?.clients.forEach((client) => {
1617
1400
  if (client.readyState === WebSocket.OPEN) {
1618
1401
  client.send(JSON.stringify({ id: WS_ID_SNACKBAR, src: 'Matterbridge', dst: 'Frontend', method: 'memory_update', params: { message, timeout } }));
1619
1402
  }
1620
1403
  });
1621
1404
  }
1622
- /**
1623
- * Sends a message to all connected clients.
1624
- *
1625
- */
1626
1405
  wssBroadcastMessage(id, method, params) {
1627
1406
  this.log.debug(`Sending a broadcast message id ${id} method ${method} params ${debugStringify(params ?? {})} to all connected clients`);
1628
- // Send the message to all connected clients
1629
1407
  this.webSocketServer?.clients.forEach((client) => {
1630
1408
  if (client.readyState === WebSocket.OPEN) {
1631
1409
  client.send(JSON.stringify({ id, src: 'Matterbridge', dst: 'Frontend', method, params }));
@@ -1633,4 +1411,3 @@ export class Frontend {
1633
1411
  });
1634
1412
  }
1635
1413
  }
1636
- //# sourceMappingURL=frontend.js.map