matterbridge 3.1.3 → 3.1.4-dev-20250715-075e722

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 (209) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.md +18 -18
  3. package/dist/cli.js +2 -91
  4. package/dist/cliEmitter.js +0 -30
  5. package/dist/clusters/export.js +0 -2
  6. package/dist/defaultConfigSchema.js +0 -24
  7. package/dist/deviceManager.js +1 -94
  8. package/dist/devices/batteryStorage.js +1 -48
  9. package/dist/devices/evse.js +10 -74
  10. package/dist/devices/export.js +0 -2
  11. package/dist/devices/heatPump.js +2 -50
  12. package/dist/devices/laundryDryer.js +6 -83
  13. package/dist/devices/laundryWasher.js +7 -91
  14. package/dist/devices/roboticVacuumCleaner.js +6 -89
  15. package/dist/devices/solarPower.js +0 -38
  16. package/dist/devices/waterHeater.js +2 -82
  17. package/dist/frontend.js +18 -423
  18. package/dist/globalMatterbridge.js +0 -47
  19. package/dist/helpers.js +0 -53
  20. package/dist/index.js +1 -30
  21. package/dist/logger/export.js +0 -1
  22. package/dist/matter/behaviors.js +0 -2
  23. package/dist/matter/clusters.js +0 -2
  24. package/dist/matter/devices.js +0 -2
  25. package/dist/matter/endpoints.js +0 -2
  26. package/dist/matter/export.js +0 -3
  27. package/dist/matter/types.js +0 -3
  28. package/dist/matterbridge.js +55 -788
  29. package/dist/matterbridgeAccessoryPlatform.js +0 -36
  30. package/dist/matterbridgeBehaviors.js +1 -61
  31. package/dist/matterbridgeDeviceTypes.js +15 -579
  32. package/dist/matterbridgeDynamicPlatform.js +0 -36
  33. package/dist/matterbridgeEndpoint.js +42 -1106
  34. package/dist/matterbridgeEndpointHelpers.js +12 -322
  35. package/dist/matterbridgePlatform.js +0 -233
  36. package/dist/matterbridgeTypes.js +0 -25
  37. package/dist/pluginManager.js +3 -269
  38. package/dist/shelly.js +7 -168
  39. package/dist/storage/export.js +0 -1
  40. package/dist/update.js +0 -54
  41. package/dist/utils/colorUtils.js +2 -263
  42. package/dist/utils/commandLine.js +0 -54
  43. package/dist/utils/copyDirectory.js +1 -38
  44. package/dist/utils/createDirectory.js +0 -33
  45. package/dist/utils/createZip.js +2 -47
  46. package/dist/utils/deepCopy.js +0 -39
  47. package/dist/utils/deepEqual.js +1 -72
  48. package/dist/utils/export.js +0 -1
  49. package/dist/utils/hex.js +0 -58
  50. package/dist/utils/isvalid.js +0 -101
  51. package/dist/utils/network.js +16 -96
  52. package/dist/utils/spawn.js +0 -18
  53. package/dist/utils/wait.js +9 -62
  54. package/npm-shrinkwrap.json +3 -3
  55. package/package.json +2 -3
  56. package/dist/cli.d.ts +0 -26
  57. package/dist/cli.d.ts.map +0 -1
  58. package/dist/cli.js.map +0 -1
  59. package/dist/cliEmitter.d.ts +0 -34
  60. package/dist/cliEmitter.d.ts.map +0 -1
  61. package/dist/cliEmitter.js.map +0 -1
  62. package/dist/clusters/export.d.ts +0 -2
  63. package/dist/clusters/export.d.ts.map +0 -1
  64. package/dist/clusters/export.js.map +0 -1
  65. package/dist/defaultConfigSchema.d.ts +0 -28
  66. package/dist/defaultConfigSchema.d.ts.map +0 -1
  67. package/dist/defaultConfigSchema.js.map +0 -1
  68. package/dist/deviceManager.d.ts +0 -112
  69. package/dist/deviceManager.d.ts.map +0 -1
  70. package/dist/deviceManager.js.map +0 -1
  71. package/dist/devices/batteryStorage.d.ts +0 -48
  72. package/dist/devices/batteryStorage.d.ts.map +0 -1
  73. package/dist/devices/batteryStorage.js.map +0 -1
  74. package/dist/devices/evse.d.ts +0 -75
  75. package/dist/devices/evse.d.ts.map +0 -1
  76. package/dist/devices/evse.js.map +0 -1
  77. package/dist/devices/export.d.ts +0 -9
  78. package/dist/devices/export.d.ts.map +0 -1
  79. package/dist/devices/export.js.map +0 -1
  80. package/dist/devices/heatPump.d.ts +0 -47
  81. package/dist/devices/heatPump.d.ts.map +0 -1
  82. package/dist/devices/heatPump.js.map +0 -1
  83. package/dist/devices/laundryDryer.d.ts +0 -87
  84. package/dist/devices/laundryDryer.d.ts.map +0 -1
  85. package/dist/devices/laundryDryer.js.map +0 -1
  86. package/dist/devices/laundryWasher.d.ts +0 -242
  87. package/dist/devices/laundryWasher.d.ts.map +0 -1
  88. package/dist/devices/laundryWasher.js.map +0 -1
  89. package/dist/devices/roboticVacuumCleaner.d.ts +0 -110
  90. package/dist/devices/roboticVacuumCleaner.d.ts.map +0 -1
  91. package/dist/devices/roboticVacuumCleaner.js.map +0 -1
  92. package/dist/devices/solarPower.d.ts +0 -40
  93. package/dist/devices/solarPower.d.ts.map +0 -1
  94. package/dist/devices/solarPower.js.map +0 -1
  95. package/dist/devices/waterHeater.d.ts +0 -111
  96. package/dist/devices/waterHeater.d.ts.map +0 -1
  97. package/dist/devices/waterHeater.js.map +0 -1
  98. package/dist/frontend.d.ts +0 -303
  99. package/dist/frontend.d.ts.map +0 -1
  100. package/dist/frontend.js.map +0 -1
  101. package/dist/globalMatterbridge.d.ts +0 -59
  102. package/dist/globalMatterbridge.d.ts.map +0 -1
  103. package/dist/globalMatterbridge.js.map +0 -1
  104. package/dist/helpers.d.ts +0 -48
  105. package/dist/helpers.d.ts.map +0 -1
  106. package/dist/helpers.js.map +0 -1
  107. package/dist/index.d.ts +0 -33
  108. package/dist/index.d.ts.map +0 -1
  109. package/dist/index.js.map +0 -1
  110. package/dist/logger/export.d.ts +0 -2
  111. package/dist/logger/export.d.ts.map +0 -1
  112. package/dist/logger/export.js.map +0 -1
  113. package/dist/matter/behaviors.d.ts +0 -2
  114. package/dist/matter/behaviors.d.ts.map +0 -1
  115. package/dist/matter/behaviors.js.map +0 -1
  116. package/dist/matter/clusters.d.ts +0 -2
  117. package/dist/matter/clusters.d.ts.map +0 -1
  118. package/dist/matter/clusters.js.map +0 -1
  119. package/dist/matter/devices.d.ts +0 -2
  120. package/dist/matter/devices.d.ts.map +0 -1
  121. package/dist/matter/devices.js.map +0 -1
  122. package/dist/matter/endpoints.d.ts +0 -2
  123. package/dist/matter/endpoints.d.ts.map +0 -1
  124. package/dist/matter/endpoints.js.map +0 -1
  125. package/dist/matter/export.d.ts +0 -5
  126. package/dist/matter/export.d.ts.map +0 -1
  127. package/dist/matter/export.js.map +0 -1
  128. package/dist/matter/types.d.ts +0 -3
  129. package/dist/matter/types.d.ts.map +0 -1
  130. package/dist/matter/types.js.map +0 -1
  131. package/dist/matterbridge.d.ts +0 -444
  132. package/dist/matterbridge.d.ts.map +0 -1
  133. package/dist/matterbridge.js.map +0 -1
  134. package/dist/matterbridgeAccessoryPlatform.d.ts +0 -42
  135. package/dist/matterbridgeAccessoryPlatform.d.ts.map +0 -1
  136. package/dist/matterbridgeAccessoryPlatform.js.map +0 -1
  137. package/dist/matterbridgeBehaviors.d.ts +0 -1340
  138. package/dist/matterbridgeBehaviors.d.ts.map +0 -1
  139. package/dist/matterbridgeBehaviors.js.map +0 -1
  140. package/dist/matterbridgeDeviceTypes.d.ts +0 -709
  141. package/dist/matterbridgeDeviceTypes.d.ts.map +0 -1
  142. package/dist/matterbridgeDeviceTypes.js.map +0 -1
  143. package/dist/matterbridgeDynamicPlatform.d.ts +0 -42
  144. package/dist/matterbridgeDynamicPlatform.d.ts.map +0 -1
  145. package/dist/matterbridgeDynamicPlatform.js.map +0 -1
  146. package/dist/matterbridgeEndpoint.d.ts +0 -1250
  147. package/dist/matterbridgeEndpoint.d.ts.map +0 -1
  148. package/dist/matterbridgeEndpoint.js.map +0 -1
  149. package/dist/matterbridgeEndpointHelpers.d.ts +0 -3198
  150. package/dist/matterbridgeEndpointHelpers.d.ts.map +0 -1
  151. package/dist/matterbridgeEndpointHelpers.js.map +0 -1
  152. package/dist/matterbridgePlatform.d.ts +0 -310
  153. package/dist/matterbridgePlatform.d.ts.map +0 -1
  154. package/dist/matterbridgePlatform.js.map +0 -1
  155. package/dist/matterbridgeTypes.d.ts +0 -195
  156. package/dist/matterbridgeTypes.d.ts.map +0 -1
  157. package/dist/matterbridgeTypes.js.map +0 -1
  158. package/dist/pluginManager.d.ts +0 -291
  159. package/dist/pluginManager.d.ts.map +0 -1
  160. package/dist/pluginManager.js.map +0 -1
  161. package/dist/shelly.d.ts +0 -174
  162. package/dist/shelly.d.ts.map +0 -1
  163. package/dist/shelly.js.map +0 -1
  164. package/dist/storage/export.d.ts +0 -2
  165. package/dist/storage/export.d.ts.map +0 -1
  166. package/dist/storage/export.js.map +0 -1
  167. package/dist/update.d.ts +0 -59
  168. package/dist/update.d.ts.map +0 -1
  169. package/dist/update.js.map +0 -1
  170. package/dist/utils/colorUtils.d.ts +0 -117
  171. package/dist/utils/colorUtils.d.ts.map +0 -1
  172. package/dist/utils/colorUtils.js.map +0 -1
  173. package/dist/utils/commandLine.d.ts +0 -59
  174. package/dist/utils/commandLine.d.ts.map +0 -1
  175. package/dist/utils/commandLine.js.map +0 -1
  176. package/dist/utils/copyDirectory.d.ts +0 -33
  177. package/dist/utils/copyDirectory.d.ts.map +0 -1
  178. package/dist/utils/copyDirectory.js.map +0 -1
  179. package/dist/utils/createDirectory.d.ts +0 -34
  180. package/dist/utils/createDirectory.d.ts.map +0 -1
  181. package/dist/utils/createDirectory.js.map +0 -1
  182. package/dist/utils/createZip.d.ts +0 -39
  183. package/dist/utils/createZip.d.ts.map +0 -1
  184. package/dist/utils/createZip.js.map +0 -1
  185. package/dist/utils/deepCopy.d.ts +0 -32
  186. package/dist/utils/deepCopy.d.ts.map +0 -1
  187. package/dist/utils/deepCopy.js.map +0 -1
  188. package/dist/utils/deepEqual.d.ts +0 -54
  189. package/dist/utils/deepEqual.d.ts.map +0 -1
  190. package/dist/utils/deepEqual.js.map +0 -1
  191. package/dist/utils/export.d.ts +0 -12
  192. package/dist/utils/export.d.ts.map +0 -1
  193. package/dist/utils/export.js.map +0 -1
  194. package/dist/utils/hex.d.ts +0 -49
  195. package/dist/utils/hex.d.ts.map +0 -1
  196. package/dist/utils/hex.js.map +0 -1
  197. package/dist/utils/isvalid.d.ts +0 -103
  198. package/dist/utils/isvalid.d.ts.map +0 -1
  199. package/dist/utils/isvalid.js.map +0 -1
  200. package/dist/utils/network.d.ts +0 -76
  201. package/dist/utils/network.d.ts.map +0 -1
  202. package/dist/utils/network.js.map +0 -1
  203. package/dist/utils/spawn.d.ts +0 -11
  204. package/dist/utils/spawn.d.ts.map +0 -1
  205. package/dist/utils/spawn.js.map +0 -1
  206. package/dist/utils/wait.d.ts +0 -56
  207. package/dist/utils/wait.d.ts.map +0 -1
  208. package/dist/utils/wait.js.map +0 -1
  209. /package/bin/{matterbridge → matterbridge.js} +0 -0
package/dist/frontend.js CHANGED
@@ -1,126 +1,30 @@
1
- /**
2
- * This file contains the class Frontend.
3
- *
4
- * @file frontend.ts
5
- * @author Luca Liguori
6
- * @created 2025-01-13
7
- * @version 1.1.0
8
- * @license Apache-2.0
9
- *
10
- * Copyright 2025, 2026, 2027 Luca Liguori.
11
- *
12
- * Licensed under the Apache License, Version 2.0 (the "License");
13
- * you may not use this file except in compliance with the License.
14
- * You may obtain a copy of the License at
15
- *
16
- * http://www.apache.org/licenses/LICENSE-2.0
17
- *
18
- * Unless required by applicable law or agreed to in writing, software
19
- * distributed under the License is distributed on an "AS IS" BASIS,
20
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21
- * See the License for the specific language governing permissions and
22
- * limitations under the License.
23
- */
24
- // Node modules
25
1
  import { createServer } from 'node:http';
26
2
  import https from 'node:https';
27
3
  import os from 'node:os';
28
4
  import path from 'node:path';
29
5
  import { promises as fs } from 'node:fs';
30
6
  import EventEmitter from 'node:events';
31
- // Third-party modules
32
7
  import express from 'express';
33
8
  import WebSocket, { WebSocketServer } from 'ws';
34
9
  import multer from 'multer';
35
- // AnsiLogger module
36
10
  import { AnsiLogger, stringify, debugStringify, CYAN, db, er, nf, rs, UNDERLINE, UNDERLINEOFF, YELLOW, nt } from 'node-ansi-logger';
37
- // @matter
38
11
  import { Logger, LogLevel as MatterLogLevel, LogFormat as MatterLogFormat, Lifecycle } from '@matter/main';
39
12
  import { BridgedDeviceBasicInformation, PowerSource } from '@matter/main/clusters';
40
- // Matterbridge
41
13
  import { createZip, isValidArray, isValidNumber, isValidObject, isValidString, isValidBoolean, withTimeout, hasParameter } from './utils/export.js';
42
14
  import { plg } from './matterbridgeTypes.js';
43
15
  import { capitalizeFirstLetter, getAttribute } from './matterbridgeEndpointHelpers.js';
44
16
  import { cliEmitter, lastCpuUsage } from './cliEmitter.js';
45
- /**
46
- * Websocket message ID for logging.
47
- *
48
- * @constant {number}
49
- */
50
17
  export const WS_ID_LOG = 0;
51
- /**
52
- * Websocket message ID indicating a refresh is needed.
53
- *
54
- * @constant {number}
55
- */
56
18
  export const WS_ID_REFRESH_NEEDED = 1;
57
- /**
58
- * Websocket message ID indicating a restart is needed.
59
- *
60
- * @constant {number}
61
- */
62
19
  export const WS_ID_RESTART_NEEDED = 2;
63
- /**
64
- * Websocket message ID indicating a cpu update.
65
- *
66
- * @constant {number}
67
- */
68
20
  export const WS_ID_CPU_UPDATE = 3;
69
- /**
70
- * Websocket message ID indicating a memory update.
71
- *
72
- * @constant {number}
73
- */
74
21
  export const WS_ID_MEMORY_UPDATE = 4;
75
- /**
76
- * Websocket message ID indicating an uptime update.
77
- *
78
- * @constant {number}
79
- */
80
22
  export const WS_ID_UPTIME_UPDATE = 5;
81
- /**
82
- * Websocket message ID indicating a snackbar message.
83
- *
84
- * @constant {number}
85
- */
86
23
  export const WS_ID_SNACKBAR = 6;
87
- /**
88
- * Websocket message ID indicating matterbridge has un update available.
89
- *
90
- * @constant {number}
91
- */
92
24
  export const WS_ID_UPDATE_NEEDED = 7;
93
- /**
94
- * Websocket message ID indicating a state update.
95
- *
96
- * @constant {number}
97
- */
98
25
  export const WS_ID_STATEUPDATE = 8;
99
- /**
100
- * Websocket message ID indicating to close a permanent snackbar message.
101
- *
102
- * @constant {number}
103
- */
104
26
  export const WS_ID_CLOSE_SNACKBAR = 9;
105
- /**
106
- * Websocket message ID indicating a shelly system update.
107
- * check:
108
- * curl -k http://127.0.0.1:8101/api/updates/sys/check
109
- * perform:
110
- * curl -k http://127.0.0.1:8101/api/updates/sys/perform
111
- *
112
- * @constant {number}
113
- */
114
27
  export const WS_ID_SHELLY_SYS_UPDATE = 100;
115
- /**
116
- * Websocket message ID indicating a shelly main update.
117
- * check:
118
- * curl -k http://127.0.0.1:8101/api/updates/main/check
119
- * perform:
120
- * curl -k http://127.0.0.1:8101/api/updates/main/perform
121
- *
122
- * @constant {number}
123
- */
124
28
  export const WS_ID_SHELLY_MAIN_UPDATE = 101;
125
29
  export class Frontend extends EventEmitter {
126
30
  matterbridge;
@@ -134,7 +38,7 @@ export class Frontend extends EventEmitter {
134
38
  constructor(matterbridge) {
135
39
  super();
136
40
  this.matterbridge = matterbridge;
137
- this.log = new AnsiLogger({ logName: 'Frontend', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: hasParameter('debug') ? "debug" /* LogLevel.DEBUG */ : "info" /* LogLevel.INFO */ });
41
+ this.log = new AnsiLogger({ logName: 'Frontend', logTimestampFormat: 4, logLevel: hasParameter('debug') ? "debug" : "info" });
138
42
  }
139
43
  set logLevel(logLevel) {
140
44
  this.log.logLevel = logLevel;
@@ -142,41 +46,12 @@ export class Frontend extends EventEmitter {
142
46
  async start(port = 8283) {
143
47
  this.port = port;
144
48
  this.log.debug(`Initializing the frontend ${hasParameter('ssl') ? 'https' : 'http'} server on port ${YELLOW}${this.port}${db}`);
145
- // Initialize multer with the upload directory
146
49
  const uploadDir = path.join(this.matterbridge.matterbridgeDirectory, 'uploads');
147
50
  await fs.mkdir(uploadDir, { recursive: true });
148
51
  const upload = multer({ dest: uploadDir });
149
- // Create the express app that serves the frontend
150
52
  this.expressApp = express();
151
- // Inject logging/debug wrapper for route/middleware registration
152
- /*
153
- const methods = ['get', 'post', 'put', 'delete', 'use'];
154
- for (const method of methods) {
155
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
156
- const original = (this.expressApp as any)[method].bind(this.expressApp);
157
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
158
- (this.expressApp as any)[method] = (path: any, ...rest: any) => {
159
- try {
160
- console.log(`[DEBUG] Registering ${method.toUpperCase()} route:`, path);
161
- return original(path, ...rest);
162
- } catch (err) {
163
- console.error(`[ERROR] Failed to register route: ${path}`);
164
- throw err;
165
- }
166
- };
167
- }
168
- */
169
- // Log all requests to the server for debugging
170
- /*
171
- this.expressApp.use((req, res, next) => {
172
- this.log.debug(`***Received request on expressApp: ${req.method} ${req.url}`);
173
- next();
174
- });
175
- */
176
- // Serve static files from '/static' endpoint
177
53
  this.expressApp.use(express.static(path.join(this.matterbridge.rootDirectory, 'frontend/build')));
178
54
  if (!hasParameter('ssl')) {
179
- // Create an HTTP server and attach the express app
180
55
  try {
181
56
  this.httpServer = createServer(this.expressApp);
182
57
  }
@@ -185,7 +60,6 @@ export class Frontend extends EventEmitter {
185
60
  this.emit('server_error', error);
186
61
  return;
187
62
  }
188
- // Listen on the specified port
189
63
  if (hasParameter('ingress')) {
190
64
  this.httpServer.listen(this.port, '0.0.0.0', () => {
191
65
  this.log.info(`The frontend http server is listening on ${UNDERLINE}http://0.0.0.0:${this.port}${UNDERLINEOFF}${rs}`);
@@ -217,7 +91,6 @@ export class Frontend extends EventEmitter {
217
91
  });
218
92
  }
219
93
  else {
220
- // Load the SSL certificate, the private key and optionally the CA certificate
221
94
  let cert;
222
95
  try {
223
96
  cert = await fs.readFile(path.join(this.matterbridge.matterbridgeDirectory, 'certs/cert.pem'), 'utf8');
@@ -247,7 +120,6 @@ export class Frontend extends EventEmitter {
247
120
  this.log.info(`CA certificate file ${path.join(this.matterbridge.matterbridgeDirectory, 'certs/ca.pem')} not loaded: ${error}`);
248
121
  }
249
122
  const serverOptions = { cert, key, ca };
250
- // Create an HTTPS server with the SSL certificate and private key (ca is optional) and attach the express app
251
123
  try {
252
124
  this.httpsServer = https.createServer(serverOptions, this.expressApp);
253
125
  }
@@ -256,7 +128,6 @@ export class Frontend extends EventEmitter {
256
128
  this.emit('server_error', error);
257
129
  return;
258
130
  }
259
- // Listen on the specified port
260
131
  if (hasParameter('ingress')) {
261
132
  this.httpsServer.listen(this.port, '0.0.0.0', () => {
262
133
  this.log.info(`The frontend https server is listening on ${UNDERLINE}https://0.0.0.0:${this.port}${UNDERLINEOFF}${rs}`);
@@ -289,18 +160,16 @@ export class Frontend extends EventEmitter {
289
160
  }
290
161
  if (this.initializeError)
291
162
  return;
292
- // Create a WebSocket server and attach it to the http or https server
293
163
  const wssPort = this.port;
294
164
  const wssHost = hasParameter('ssl') ? `wss://${this.matterbridge.systemInformation.ipv4Address}:${wssPort}` : `ws://${this.matterbridge.systemInformation.ipv4Address}:${wssPort}`;
295
165
  this.webSocketServer = new WebSocketServer(hasParameter('ssl') ? { server: this.httpsServer } : { server: this.httpServer });
296
166
  this.webSocketServer.on('connection', (ws, request) => {
297
167
  const clientIp = request.socket.remoteAddress;
298
- // Set the global logger callback for the WebSocketServer
299
- let callbackLogLevel = "notice" /* LogLevel.NOTICE */;
300
- if (this.matterbridge.matterbridgeInformation.loggerLevel === "info" /* LogLevel.INFO */ || this.matterbridge.matterbridgeInformation.matterLoggerLevel === MatterLogLevel.INFO)
301
- callbackLogLevel = "info" /* LogLevel.INFO */;
302
- if (this.matterbridge.matterbridgeInformation.loggerLevel === "debug" /* LogLevel.DEBUG */ || this.matterbridge.matterbridgeInformation.matterLoggerLevel === MatterLogLevel.DEBUG)
303
- callbackLogLevel = "debug" /* LogLevel.DEBUG */;
168
+ let callbackLogLevel = "notice";
169
+ if (this.matterbridge.matterbridgeInformation.loggerLevel === "info" || this.matterbridge.matterbridgeInformation.matterLoggerLevel === MatterLogLevel.INFO)
170
+ callbackLogLevel = "info";
171
+ if (this.matterbridge.matterbridgeInformation.loggerLevel === "debug" || this.matterbridge.matterbridgeInformation.matterLoggerLevel === MatterLogLevel.DEBUG)
172
+ callbackLogLevel = "debug";
304
173
  AnsiLogger.setGlobalCallback(this.wssSendMessage.bind(this), callbackLogLevel);
305
174
  this.log.debug(`WebSocketServer logger global callback set to ${callbackLogLevel}`);
306
175
  this.log.info(`WebSocketServer client "${clientIp}" connected to Matterbridge`);
@@ -335,7 +204,6 @@ export class Frontend extends EventEmitter {
335
204
  this.webSocketServer.on('error', (ws, error) => {
336
205
  this.log.error(`WebSocketServer error: ${error}`);
337
206
  });
338
- // Subscribe to cli events
339
207
  cliEmitter.removeAllListeners();
340
208
  cliEmitter.on('uptime', (systemUptime, processUptime) => {
341
209
  this.wssSendUptimeUpdate(systemUptime, processUptime);
@@ -346,8 +214,6 @@ export class Frontend extends EventEmitter {
346
214
  cliEmitter.on('cpu', (cpuUsage) => {
347
215
  this.wssSendCpuUpdate(cpuUsage);
348
216
  });
349
- // Endpoint to validate login code
350
- // curl -X POST "http://localhost:8283/api/login" -H "Content-Type: application/json" -d "{\"password\":\"Here\"}"
351
217
  this.expressApp.post('/api/login', express.json(), async (req, res) => {
352
218
  const { password } = req.body;
353
219
  this.log.debug('The frontend sent /api/login', password);
@@ -366,27 +232,23 @@ export class Frontend extends EventEmitter {
366
232
  this.log.warn('/api/login error wrong password');
367
233
  res.json({ valid: false });
368
234
  }
369
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
370
235
  }
371
236
  catch (error) {
372
237
  this.log.error('/api/login error getting password');
373
238
  res.json({ valid: false });
374
239
  }
375
240
  });
376
- // Endpoint to provide health check for docker
377
241
  this.expressApp.get('/health', (req, res) => {
378
242
  this.log.debug('Express received /health');
379
243
  const healthStatus = {
380
- status: 'ok', // Indicate service is healthy
381
- uptime: process.uptime(), // Server uptime in seconds
382
- timestamp: new Date().toISOString(), // Current timestamp
244
+ status: 'ok',
245
+ uptime: process.uptime(),
246
+ timestamp: new Date().toISOString(),
383
247
  };
384
248
  res.status(200).json(healthStatus);
385
249
  });
386
- // Endpoint to provide memory usage details
387
250
  this.expressApp.get('/memory', async (req, res) => {
388
251
  this.log.debug('Express received /memory');
389
- // Memory usage from process
390
252
  const memoryUsageRaw = process.memoryUsage();
391
253
  const memoryUsage = {
392
254
  rss: this.formatMemoryUsage(memoryUsageRaw.rss),
@@ -395,13 +257,10 @@ export class Frontend extends EventEmitter {
395
257
  external: this.formatMemoryUsage(memoryUsageRaw.external),
396
258
  arrayBuffers: this.formatMemoryUsage(memoryUsageRaw.arrayBuffers),
397
259
  };
398
- // V8 heap statistics
399
260
  const { default: v8 } = await import('node:v8');
400
261
  const heapStatsRaw = v8.getHeapStatistics();
401
262
  const heapSpacesRaw = v8.getHeapSpaceStatistics();
402
- // Format heapStats
403
263
  const heapStats = Object.fromEntries(Object.entries(heapStatsRaw).map(([key, value]) => [key, this.formatMemoryUsage(value)]));
404
- // Format heapSpaces
405
264
  const heapSpaces = heapSpacesRaw.map((space) => ({
406
265
  ...space,
407
266
  space_size: this.formatMemoryUsage(space.space_size),
@@ -419,23 +278,19 @@ export class Frontend extends EventEmitter {
419
278
  };
420
279
  res.status(200).json(memoryReport);
421
280
  });
422
- // Endpoint to provide settings
423
281
  this.expressApp.get('/api/settings', express.json(), async (req, res) => {
424
282
  this.log.debug('The frontend sent /api/settings');
425
283
  res.json(await this.getApiSettings());
426
284
  });
427
- // Endpoint to provide plugins
428
285
  this.expressApp.get('/api/plugins', async (req, res) => {
429
286
  this.log.debug('The frontend sent /api/plugins');
430
287
  res.json(this.getBaseRegisteredPlugins());
431
288
  });
432
- // Endpoint to provide devices
433
289
  this.expressApp.get('/api/devices', async (req, res) => {
434
290
  this.log.debug('The frontend sent /api/devices');
435
291
  const devices = await this.getDevices();
436
292
  res.json(devices);
437
293
  });
438
- // Endpoint to view the matterbridge log
439
294
  this.expressApp.get('/api/view-mblog', async (req, res) => {
440
295
  this.log.debug('The frontend sent /api/view-mblog');
441
296
  try {
@@ -448,7 +303,6 @@ export class Frontend extends EventEmitter {
448
303
  res.status(500).send('Error reading matterbridge log file. Please enable the matterbridge log on file in the settings.');
449
304
  }
450
305
  });
451
- // Endpoint to view the matter.js log
452
306
  this.expressApp.get('/api/view-mjlog', async (req, res) => {
453
307
  this.log.debug('The frontend sent /api/view-mjlog');
454
308
  try {
@@ -461,7 +315,6 @@ export class Frontend extends EventEmitter {
461
315
  res.status(500).send('Error reading matter log file. Please enable the matter log on file in the settings.');
462
316
  }
463
317
  });
464
- // Endpoint to view the shelly log
465
318
  this.expressApp.get('/api/shellyviewsystemlog', async (req, res) => {
466
319
  this.log.debug('The frontend sent /api/shellyviewsystemlog');
467
320
  try {
@@ -474,11 +327,9 @@ export class Frontend extends EventEmitter {
474
327
  res.status(500).send('Error reading shelly log file. Please create the shelly system log before loading it.');
475
328
  }
476
329
  });
477
- // Endpoint to download the matterbridge log
478
330
  this.expressApp.get('/api/download-mblog', async (req, res) => {
479
331
  this.log.debug(`The frontend sent /api/download-mblog ${path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterbridgeLoggerFile)}`);
480
332
  try {
481
- // eslint-disable-next-line n/no-unsupported-features/node-builtins
482
333
  await fs.access(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterbridgeLoggerFile), fs.constants.F_OK);
483
334
  const data = await fs.readFile(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterbridgeLoggerFile), 'utf8');
484
335
  await fs.writeFile(path.join(os.tmpdir(), this.matterbridge.matterbridgeLoggerFile), data, 'utf-8');
@@ -489,18 +340,15 @@ export class Frontend extends EventEmitter {
489
340
  }
490
341
  res.type('text/plain');
491
342
  res.download(path.join(os.tmpdir(), this.matterbridge.matterbridgeLoggerFile), 'matterbridge.log', (error) => {
492
- /* istanbul ignore if */
493
343
  if (error) {
494
344
  this.log.error(`Error downloading log file ${this.matterbridge.matterbridgeLoggerFile}: ${error instanceof Error ? error.message : error}`);
495
345
  res.status(500).send('Error downloading the matterbridge log file');
496
346
  }
497
347
  });
498
348
  });
499
- // Endpoint to download the matter log
500
349
  this.expressApp.get('/api/download-mjlog', async (req, res) => {
501
350
  this.log.debug(`The frontend sent /api/download-mjlog ${path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterbridgeLoggerFile)}`);
502
351
  try {
503
- // eslint-disable-next-line n/no-unsupported-features/node-builtins
504
352
  await fs.access(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterLoggerFile), fs.constants.F_OK);
505
353
  const data = await fs.readFile(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterLoggerFile), 'utf8');
506
354
  await fs.writeFile(path.join(os.tmpdir(), this.matterbridge.matterLoggerFile), data, 'utf-8');
@@ -511,18 +359,15 @@ export class Frontend extends EventEmitter {
511
359
  }
512
360
  res.type('text/plain');
513
361
  res.download(path.join(os.tmpdir(), this.matterbridge.matterLoggerFile), 'matter.log', (error) => {
514
- /* istanbul ignore if */
515
362
  if (error) {
516
363
  this.log.error(`Error downloading log file ${this.matterbridge.matterLoggerFile}: ${error instanceof Error ? error.message : error}`);
517
364
  res.status(500).send('Error downloading the matter log file');
518
365
  }
519
366
  });
520
367
  });
521
- // Endpoint to download the shelly log
522
368
  this.expressApp.get('/api/shellydownloadsystemlog', async (req, res) => {
523
369
  this.log.debug('The frontend sent /api/shellydownloadsystemlog');
524
370
  try {
525
- // eslint-disable-next-line n/no-unsupported-features/node-builtins
526
371
  await fs.access(path.join(this.matterbridge.matterbridgeDirectory, 'shelly.log'), fs.constants.F_OK);
527
372
  const data = await fs.readFile(path.join(this.matterbridge.matterbridgeDirectory, 'shelly.log'), 'utf8');
528
373
  await fs.writeFile(path.join(os.tmpdir(), 'shelly.log'), data, 'utf-8');
@@ -533,90 +378,74 @@ export class Frontend extends EventEmitter {
533
378
  }
534
379
  res.type('text/plain');
535
380
  res.download(path.join(os.tmpdir(), 'shelly.log'), 'shelly.log', (error) => {
536
- /* istanbul ignore if */
537
381
  if (error) {
538
382
  this.log.error(`Error downloading Shelly system log file: ${error instanceof Error ? error.message : error}`);
539
383
  res.status(500).send('Error downloading Shelly system log file');
540
384
  }
541
385
  });
542
386
  });
543
- // Endpoint to download the matterbridge storage directory
544
387
  this.expressApp.get('/api/download-mbstorage', async (req, res) => {
545
388
  this.log.debug('The frontend sent /api/download-mbstorage');
546
389
  await createZip(path.join(os.tmpdir(), `matterbridge.${this.matterbridge.nodeStorageName}.zip`), path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.nodeStorageName));
547
390
  res.download(path.join(os.tmpdir(), `matterbridge.${this.matterbridge.nodeStorageName}.zip`), `matterbridge.${this.matterbridge.nodeStorageName}.zip`, (error) => {
548
- /* istanbul ignore if */
549
391
  if (error) {
550
392
  this.log.error(`Error downloading file ${`matterbridge.${this.matterbridge.nodeStorageName}.zip`}: ${error instanceof Error ? error.message : error}`);
551
393
  res.status(500).send('Error downloading the matterbridge storage file');
552
394
  }
553
395
  });
554
396
  });
555
- // Endpoint to download the matter storage file
556
397
  this.expressApp.get('/api/download-mjstorage', async (req, res) => {
557
398
  this.log.debug('The frontend sent /api/download-mjstorage');
558
399
  await createZip(path.join(os.tmpdir(), `matterbridge.${this.matterbridge.matterStorageName}.zip`), path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterStorageName));
559
400
  res.download(path.join(os.tmpdir(), `matterbridge.${this.matterbridge.matterStorageName}.zip`), `matterbridge.${this.matterbridge.matterStorageName}.zip`, (error) => {
560
- /* istanbul ignore if */
561
401
  if (error) {
562
402
  this.log.error(`Error downloading the matter storage matterbridge.${this.matterbridge.matterStorageName}.zip: ${error instanceof Error ? error.message : error}`);
563
403
  res.status(500).send('Error downloading the matter storage zip file');
564
404
  }
565
405
  });
566
406
  });
567
- // Endpoint to download the matterbridge plugin directory
568
407
  this.expressApp.get('/api/download-pluginstorage', async (req, res) => {
569
408
  this.log.debug('The frontend sent /api/download-pluginstorage');
570
409
  await createZip(path.join(os.tmpdir(), `matterbridge.pluginstorage.zip`), this.matterbridge.matterbridgePluginDirectory);
571
410
  res.download(path.join(os.tmpdir(), `matterbridge.pluginstorage.zip`), `matterbridge.pluginstorage.zip`, (error) => {
572
- /* istanbul ignore if */
573
411
  if (error) {
574
412
  this.log.error(`Error downloading file matterbridge.pluginstorage.zip: ${error instanceof Error ? error.message : error}`);
575
413
  res.status(500).send('Error downloading the matterbridge plugin storage file');
576
414
  }
577
415
  });
578
416
  });
579
- // Endpoint to download the matterbridge plugin config files
580
417
  this.expressApp.get('/api/download-pluginconfig', async (req, res) => {
581
418
  this.log.debug('The frontend sent /api/download-pluginconfig');
582
419
  await createZip(path.join(os.tmpdir(), `matterbridge.pluginconfig.zip`), path.relative(process.cwd(), path.join(this.matterbridge.matterbridgeDirectory, '*.config.json')));
583
420
  res.download(path.join(os.tmpdir(), `matterbridge.pluginconfig.zip`), `matterbridge.pluginconfig.zip`, (error) => {
584
- /* istanbul ignore if */
585
421
  if (error) {
586
422
  this.log.error(`Error downloading file matterbridge.pluginconfig.zip: ${error instanceof Error ? error.message : error}`);
587
423
  res.status(500).send('Error downloading the matterbridge plugin config file');
588
424
  }
589
425
  });
590
426
  });
591
- // Endpoint to download the matterbridge backup (created with the backup command)
592
427
  this.expressApp.get('/api/download-backup', async (req, res) => {
593
428
  this.log.debug('The frontend sent /api/download-backup');
594
429
  res.download(path.join(os.tmpdir(), `matterbridge.backup.zip`), `matterbridge.backup.zip`, (error) => {
595
- /* istanbul ignore if */
596
430
  if (error) {
597
431
  this.log.error(`Error downloading file matterbridge.backup.zip: ${error instanceof Error ? error.message : error}`);
598
432
  res.status(500).send(`Error downloading file matterbridge.backup.zip: ${error instanceof Error ? error.message : error}`);
599
433
  }
600
434
  });
601
435
  });
602
- // Endpoint to upload a package
603
436
  this.expressApp.post('/api/uploadpackage', upload.single('file'), async (req, res) => {
604
437
  const { filename } = req.body;
605
438
  const file = req.file;
606
- /* istanbul ignore if */
607
439
  if (!file || !filename) {
608
440
  this.log.error(`uploadpackage: invalid request: file and filename are required`);
609
441
  res.status(400).send('Invalid request: file and filename are required');
610
442
  return;
611
443
  }
612
444
  this.wssSendSnackbarMessage(`Installing package ${filename}. Please wait...`, 0);
613
- // Define the path where the plugin file will be saved
614
445
  const filePath = path.join(this.matterbridge.matterbridgeDirectory, 'uploads', filename);
615
446
  try {
616
- // Move the uploaded file to the specified path
617
447
  await fs.rename(file.path, filePath);
618
448
  this.log.info(`File ${plg}${filename}${nf} uploaded successfully`);
619
- // Install the plugin package
620
449
  if (filename.endsWith('.tgz')) {
621
450
  const { spawnCommand } = await import('./utils/spawn.js');
622
451
  await spawnCommand(this.matterbridge, 'npm', ['install', '-g', filePath, '--omit=dev', '--verbose']);
@@ -636,7 +465,6 @@ export class Frontend extends EventEmitter {
636
465
  res.status(500).send(`Error uploading or installing plugin package ${filename}`);
637
466
  }
638
467
  });
639
- // Fallback for routing (must be the last route)
640
468
  this.expressApp.use((req, res) => {
641
469
  this.log.debug(`The frontend sent ${req.url} method ${req.method}: sending index.html as fallback`);
642
470
  res.sendFile(path.join(this.matterbridge.rootDirectory, 'frontend/build/index.html'));
@@ -645,16 +473,13 @@ export class Frontend extends EventEmitter {
645
473
  }
646
474
  async stop() {
647
475
  this.log.debug('Stopping the frontend...');
648
- // Remove listeners from the express app
649
476
  if (this.expressApp) {
650
477
  this.expressApp.removeAllListeners();
651
478
  this.expressApp = undefined;
652
479
  this.log.debug('Frontend app closed successfully');
653
480
  }
654
- // Close the WebSocket server
655
481
  if (this.webSocketServer) {
656
482
  this.log.debug('Closing WebSocket server...');
657
- // Close all active connections
658
483
  this.webSocketServer.clients.forEach((client) => {
659
484
  if (client.readyState === WebSocket.OPEN) {
660
485
  client.close();
@@ -674,7 +499,6 @@ export class Frontend extends EventEmitter {
674
499
  this.webSocketServer.removeAllListeners();
675
500
  this.webSocketServer = undefined;
676
501
  }
677
- // Close the http server
678
502
  if (this.httpServer) {
679
503
  this.log.debug('Closing http server...');
680
504
  await withTimeout(new Promise((resolve) => {
@@ -692,7 +516,6 @@ export class Frontend extends EventEmitter {
692
516
  this.httpServer = undefined;
693
517
  this.log.debug('Frontend http server closed successfully');
694
518
  }
695
- // Close the https server
696
519
  if (this.httpsServer) {
697
520
  this.log.debug('Closing https server...');
698
521
  await withTimeout(new Promise((resolve) => {
@@ -712,7 +535,6 @@ export class Frontend extends EventEmitter {
712
535
  }
713
536
  this.log.debug('Frontend stopped successfully');
714
537
  }
715
- // Function to format bytes to KB, MB, or GB
716
538
  formatMemoryUsage = (bytes) => {
717
539
  if (bytes >= 1024 ** 3) {
718
540
  return `${(bytes / 1024 ** 3).toFixed(2)} GB`;
@@ -724,7 +546,6 @@ export class Frontend extends EventEmitter {
724
546
  return `${(bytes / 1024).toFixed(2)} KB`;
725
547
  }
726
548
  };
727
- // Function to format system uptime with only the most significant unit
728
549
  formatOsUpTime = (seconds) => {
729
550
  if (seconds >= 86400) {
730
551
  const days = Math.floor(seconds / 86400);
@@ -740,13 +561,7 @@ export class Frontend extends EventEmitter {
740
561
  }
741
562
  return `${seconds} second${seconds !== 1 ? 's' : ''}`;
742
563
  };
743
- /**
744
- * Retrieves the api settings data.
745
- *
746
- * @returns {Promise<{ matterbridgeInformation: MatterbridgeInformation, systemInformation: SystemInformation }>} A promise that resolve in the api settings object.
747
- */
748
564
  async getApiSettings() {
749
- // Update the system information
750
565
  this.matterbridge.systemInformation.totalMemory = this.formatMemoryUsage(os.totalmem());
751
566
  this.matterbridge.systemInformation.freeMemory = this.formatMemoryUsage(os.freemem());
752
567
  this.matterbridge.systemInformation.systemUptime = this.formatOsUpTime(os.uptime());
@@ -755,7 +570,6 @@ export class Frontend extends EventEmitter {
755
570
  this.matterbridge.systemInformation.rss = this.formatMemoryUsage(process.memoryUsage().rss);
756
571
  this.matterbridge.systemInformation.heapTotal = this.formatMemoryUsage(process.memoryUsage().heapTotal);
757
572
  this.matterbridge.systemInformation.heapUsed = this.formatMemoryUsage(process.memoryUsage().heapUsed);
758
- // Update the matterbridge information
759
573
  this.matterbridge.matterbridgeInformation.bridgeMode = this.matterbridge.bridgeMode;
760
574
  this.matterbridge.matterbridgeInformation.restartMode = this.matterbridge.restartMode;
761
575
  this.matterbridge.matterbridgeInformation.profile = this.matterbridge.profile;
@@ -767,7 +581,6 @@ export class Frontend extends EventEmitter {
767
581
  this.matterbridge.matterbridgeInformation.matterPort = (await this.matterbridge.nodeContext?.get('matterport', 5540)) ?? 5540;
768
582
  this.matterbridge.matterbridgeInformation.matterDiscriminator = await this.matterbridge.nodeContext?.get('matterdiscriminator');
769
583
  this.matterbridge.matterbridgeInformation.matterPasscode = await this.matterbridge.nodeContext?.get('matterpasscode');
770
- // Update the matterbridge information in bridge mode
771
584
  if (this.matterbridge.bridgeMode === 'bridge' && this.matterbridge.serverNode) {
772
585
  this.matterbridge.matterbridgeInformation.matterbridgePaired = this.matterbridge.serverNode.state.commissioning.commissioned;
773
586
  this.matterbridge.matterbridgeInformation.matterbridgeQrPairingCode = this.matterbridge.matterbridgeInformation.matterbridgeEndAdvertise ? undefined : this.matterbridge.serverNode.state.commissioning.pairingCodes.qrPairingCode;
@@ -777,12 +590,6 @@ export class Frontend extends EventEmitter {
777
590
  }
778
591
  return { systemInformation: this.matterbridge.systemInformation, matterbridgeInformation: this.matterbridge.matterbridgeInformation };
779
592
  }
780
- /**
781
- * Retrieves the reachable attribute.
782
- *
783
- * @param {MatterbridgeEndpoint} device - The MatterbridgeEndpoint object.
784
- * @returns {boolean} The reachable attribute.
785
- */
786
593
  getReachability(device) {
787
594
  if (!device.lifecycle.isReady || device.construction.status !== Lifecycle.Status.Active)
788
595
  return false;
@@ -794,12 +601,6 @@ export class Frontend extends EventEmitter {
794
601
  return true;
795
602
  return false;
796
603
  }
797
- /**
798
- * Retrieves the power source attribute.
799
- *
800
- * @param {MatterbridgeEndpoint} endpoint - The MatterbridgeDevice to retrieve the power source from.
801
- * @returns {'ac' | 'dc' | 'ok' | 'warning' | 'critical' | undefined} The power source attribute.
802
- */
803
604
  getPowerSource(endpoint) {
804
605
  if (!endpoint.lifecycle.isReady || endpoint.construction.status !== Lifecycle.Status.Active)
805
606
  return undefined;
@@ -815,21 +616,13 @@ export class Frontend extends EventEmitter {
815
616
  }
816
617
  return;
817
618
  };
818
- // Root endpoint
819
619
  if (endpoint.hasClusterServer(PowerSource.Cluster.id))
820
620
  return powerSource(endpoint);
821
- // Child endpoints
822
621
  for (const child of endpoint.getChildEndpoints()) {
823
622
  if (child.hasClusterServer(PowerSource.Cluster.id))
824
623
  return powerSource(child);
825
624
  }
826
625
  }
827
- /**
828
- * Retrieves the commissioned status, matter pairing codes, fabrics and sessions from a given device in server mode.
829
- *
830
- * @param {MatterbridgeEndpoint} device - The MatterbridgeEndpoint to retrieve the data from.
831
- * @returns {ApiDevicesMatter | undefined} An ApiDevicesMatter object or undefined if not found.
832
- */
833
626
  getMatterDataFromDevice(device) {
834
627
  if (device.mode === 'server' && device.serverNode) {
835
628
  return {
@@ -841,13 +634,6 @@ export class Frontend extends EventEmitter {
841
634
  };
842
635
  }
843
636
  }
844
- /**
845
- * Retrieves the cluster text description from a given device.
846
- * The output is a string with the attributes description of the cluster servers in the device to show in the frontend.
847
- *
848
- * @param {MatterbridgeEndpoint} device - The MatterbridgeEndpoint to retrieve the cluster text from.
849
- * @returns {string} The attributes description of the cluster servers in the device.
850
- */
851
637
  getClusterTextFromDevice(device) {
852
638
  if (!device.lifecycle.isReady || device.construction.status !== Lifecycle.Status.Active)
853
639
  return '';
@@ -872,7 +658,6 @@ export class Frontend extends EventEmitter {
872
658
  let attributes = '';
873
659
  let supportedModes = [];
874
660
  device.forEachAttribute((clusterName, clusterId, attributeName, attributeId, attributeValue) => {
875
- // console.log(`${device.deviceName} => Cluster: ${clusterName}-${clusterId} Attribute: ${attributeName}-${attributeId} Value(${typeof attributeValue}): ${attributeValue}`);
876
661
  if (typeof attributeValue === 'undefined' || attributeValue === undefined)
877
662
  return;
878
663
  if (clusterName === 'onOff' && attributeName === 'onOff')
@@ -962,17 +747,11 @@ export class Frontend extends EventEmitter {
962
747
  if (clusterName === 'userLabel' && attributeName === 'labelList')
963
748
  attributes += `${getUserLabel(device)} `;
964
749
  });
965
- // console.log(`${device.deviceName}.forEachAttribute: ${attributes}`);
966
750
  return attributes.trimStart().trimEnd();
967
751
  }
968
- /**
969
- * Retrieves the base registered plugins sanitized for res.json().
970
- *
971
- * @returns {BaseRegisteredPlugin[]} An array of BaseRegisteredPlugin.
972
- */
973
752
  getBaseRegisteredPlugins() {
974
753
  if (this.matterbridge.hasCleanupStarted)
975
- return []; // Skip if cleanup has started
754
+ return [];
976
755
  const baseRegisteredPlugins = [];
977
756
  for (const plugin of this.matterbridge.plugins) {
978
757
  baseRegisteredPlugins.push({
@@ -1001,7 +780,6 @@ export class Frontend extends EventEmitter {
1001
780
  schemaJson: plugin.schemaJson,
1002
781
  hasWhiteList: plugin.configJson?.whiteList !== undefined,
1003
782
  hasBlackList: plugin.configJson?.blackList !== undefined,
1004
- // Childbridge mode specific data
1005
783
  paired: plugin.serverNode?.state.commissioning.commissioned,
1006
784
  qrPairingCode: this.matterbridge.matterbridgeInformation.matterbridgeEndAdvertise ? undefined : plugin.serverNode?.state.commissioning.pairingCodes.qrPairingCode,
1007
785
  manualPairingCode: this.matterbridge.matterbridgeInformation.matterbridgeEndAdvertise ? undefined : plugin.serverNode?.state.commissioning.pairingCodes.manualPairingCode,
@@ -1011,21 +789,13 @@ export class Frontend extends EventEmitter {
1011
789
  }
1012
790
  return baseRegisteredPlugins;
1013
791
  }
1014
- /**
1015
- * Retrieves the devices from Matterbridge.
1016
- *
1017
- * @param {string} [pluginName] - The name of the plugin to filter devices by.
1018
- * @returns {Promise<ApiDevices[]>} A promise that resolves to an array of ApiDevices for the frontend.
1019
- */
1020
792
  async getDevices(pluginName) {
1021
793
  if (this.matterbridge.hasCleanupStarted)
1022
- return []; // Skip if cleanup has started
794
+ return [];
1023
795
  const devices = [];
1024
796
  for (const device of this.matterbridge.devices.array()) {
1025
- // Filter by pluginName if provided
1026
797
  if (pluginName && pluginName !== device.plugin)
1027
798
  continue;
1028
- // Check if the device has the required properties
1029
799
  if (!device.plugin || !device.deviceType || !device.name || !device.deviceName || !device.serialNumber || !device.uniqueId || !device.lifecycle.isReady)
1030
800
  continue;
1031
801
  devices.push({
@@ -1045,37 +815,22 @@ export class Frontend extends EventEmitter {
1045
815
  }
1046
816
  return devices;
1047
817
  }
1048
- /**
1049
- * Retrieves the clusters from a given plugin and endpoint number.
1050
- *
1051
- * Response for /api/clusters
1052
- *
1053
- * @param {string} pluginName - The name of the plugin.
1054
- * @param {number} endpointNumber - The endpoint number.
1055
- * @returns {ApiClustersResponse | undefined} A promise that resolves to the clusters or undefined if not found.
1056
- */
1057
818
  getClusters(pluginName, endpointNumber) {
1058
819
  const endpoint = this.matterbridge.devices.array().find((d) => d.plugin === pluginName && d.maybeNumber === endpointNumber);
1059
820
  if (!endpoint || !endpoint.plugin || !endpoint.maybeNumber || !endpoint.deviceName || !endpoint.serialNumber) {
1060
821
  this.log.error(`getClusters: no device found for plugin ${pluginName} and endpoint number ${endpointNumber}`);
1061
822
  return;
1062
823
  }
1063
- // this.log.debug(`***getClusters: getting clusters for device ${endpoint.deviceName} plugin ${pluginName} endpoint number ${endpointNumber}`);
1064
- // Get the device types from the main endpoint
1065
824
  const deviceTypes = [];
1066
825
  const clusters = [];
1067
826
  endpoint.state.descriptor.deviceTypeList.forEach((d) => {
1068
827
  deviceTypes.push(d.deviceType);
1069
828
  });
1070
- // Get the clusters from the main endpoint
1071
829
  endpoint.forEachAttribute((clusterName, clusterId, attributeName, attributeId, attributeValue) => {
1072
830
  if (typeof attributeValue === 'undefined' || attributeValue === undefined)
1073
831
  return;
1074
832
  if (clusterName === 'EveHistory' && ['configDataGet', 'configDataSet', 'historyStatus', 'historyEntries', 'historyRequest', 'historySetTime', 'rLoc'].includes(attributeName))
1075
833
  return;
1076
- // console.log(
1077
- // `${idn}${endpoint.deviceName}${rs}${nf} => Cluster: ${CYAN}${clusterName} (0x${clusterId.toString(16).padStart(2, '0')})${nf} Attribute: ${CYAN}${attributeName} (0x${attributeId.toString(16).padStart(2, '0')})${nf} Value: ${YELLOW}${typeof attributeValue === 'object' ? stringify(attributeValue as object) : attributeValue}${nf}`,
1078
- // );
1079
834
  clusters.push({
1080
835
  endpoint: endpoint.number.toString(),
1081
836
  id: 'main',
@@ -1088,18 +843,12 @@ export class Frontend extends EventEmitter {
1088
843
  attributeLocalValue: attributeValue,
1089
844
  });
1090
845
  });
1091
- // Get the child endpoints
1092
846
  const childEndpoints = endpoint.getChildEndpoints();
1093
- // if (childEndpoints.length === 0) {
1094
- // this.log.debug(`***getClusters: found ${childEndpoints.length} child endpoints for device ${endpoint.deviceName} plugin ${pluginName} and endpoint number ${endpointNumber}`);
1095
- // }
1096
847
  childEndpoints.forEach((childEndpoint) => {
1097
848
  if (!childEndpoint.maybeId || !childEndpoint.maybeNumber) {
1098
849
  this.log.error(`getClusters: no child endpoint found for plugin ${pluginName} and endpoint number ${endpointNumber}`);
1099
850
  return;
1100
851
  }
1101
- // this.log.debug(`***getClusters: getting clusters for child endpoint ${childEndpoint.id} of device ${endpoint.deviceName} plugin ${pluginName} endpoint number ${childEndpoint.number}`);
1102
- // Get the device types of the child endpoint
1103
852
  const deviceTypes = [];
1104
853
  childEndpoint.state.descriptor.deviceTypeList.forEach((d) => {
1105
854
  deviceTypes.push(d.deviceType);
@@ -1109,12 +858,9 @@ export class Frontend extends EventEmitter {
1109
858
  return;
1110
859
  if (clusterName === 'EveHistory' && ['configDataGet', 'configDataSet', 'historyStatus', 'historyEntries', 'historyRequest', 'historySetTime', 'rLoc'].includes(attributeName))
1111
860
  return;
1112
- // console.log(
1113
- // `${idn}${childEndpoint.deviceName}${rs}${nf} => Cluster: ${CYAN}${clusterName} (0x${clusterId.toString(16).padStart(2, '0')})${nf} Attribute: ${CYAN}${attributeName} (0x${attributeId.toString(16).padStart(2, '0')})${nf} Value: ${YELLOW}${typeof attributeValue === 'object' ? stringify(attributeValue as object) : attributeValue}${nf}`,
1114
- // );
1115
861
  clusters.push({
1116
862
  endpoint: childEndpoint.number.toString(),
1117
- id: childEndpoint.maybeId ?? 'null', // Never happens
863
+ id: childEndpoint.maybeId ?? 'null',
1118
864
  deviceTypes,
1119
865
  clusterName: capitalizeFirstLetter(clusterName),
1120
866
  clusterId: '0x' + clusterId.toString(16).padStart(2, '0'),
@@ -1127,13 +873,6 @@ export class Frontend extends EventEmitter {
1127
873
  });
1128
874
  return { plugin: endpoint.plugin, deviceName: endpoint.deviceName, serialNumber: endpoint.serialNumber, endpoint: endpoint.maybeNumber, deviceTypes, clusters };
1129
875
  }
1130
- /**
1131
- * Handles incoming websocket messages for the Matterbridge frontend.
1132
- *
1133
- * @param {WebSocket} client - The websocket client that sent the message.
1134
- * @param {WebSocket.RawData} message - The raw data of the message received from the client.
1135
- * @returns {Promise<void>} A promise that resolves when the message has been handled.
1136
- */
1137
876
  async wsMessageHandler(client, message) {
1138
877
  let data;
1139
878
  try {
@@ -1180,41 +919,32 @@ export class Frontend extends EventEmitter {
1180
919
  this.wssSendSnackbarMessage(`Installed package ${data.params.packageName}`, 5, 'success');
1181
920
  const packageName = data.params.packageName.replace(/@.*$/, '');
1182
921
  if (data.params.restart === false && packageName !== 'matterbridge') {
1183
- // The install comes from InstallPlugins
1184
922
  this.matterbridge.plugins
1185
923
  .add(packageName)
1186
924
  .then((plugin) => {
1187
925
  if (plugin) {
1188
- // The plugin is not registered
1189
926
  this.wssSendSnackbarMessage(`Added plugin ${packageName}`, 5, 'success');
1190
927
  this.matterbridge.plugins
1191
928
  .load(plugin, true, 'The plugin has been added', true)
1192
- // eslint-disable-next-line promise/no-nesting
1193
929
  .then(() => {
1194
930
  this.wssSendSnackbarMessage(`Started plugin ${packageName}`, 5, 'success');
1195
931
  this.wssSendRefreshRequired('plugins');
1196
932
  return;
1197
933
  })
1198
- // eslint-disable-next-line promise/no-nesting
1199
934
  .catch((_error) => {
1200
- //
1201
935
  });
1202
936
  }
1203
937
  else {
1204
- // The plugin is already registered
1205
938
  this.wssSendSnackbarMessage(`Restart required`, 0);
1206
939
  this.wssSendRefreshRequired('plugins');
1207
940
  this.wssSendRestartRequired();
1208
941
  }
1209
942
  return;
1210
943
  })
1211
- // eslint-disable-next-line promise/no-nesting
1212
944
  .catch((_error) => {
1213
- //
1214
945
  });
1215
946
  }
1216
947
  else {
1217
- // The package is matterbridge
1218
948
  if (this.matterbridge.restartMode !== '') {
1219
949
  this.wssSendSnackbarMessage(`Restarting matterbridge...`, 0);
1220
950
  this.matterbridge.shutdownProcess();
@@ -1237,7 +967,6 @@ export class Frontend extends EventEmitter {
1237
967
  client.send(JSON.stringify({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, error: 'Wrong parameter packageName in /api/uninstall' }));
1238
968
  return;
1239
969
  }
1240
- // The package is a plugin
1241
970
  const plugin = this.matterbridge.plugins.get(data.params.packageName);
1242
971
  if (plugin) {
1243
972
  await this.matterbridge.plugins.shutdown(plugin, 'The plugin has been removed.', true);
@@ -1246,7 +975,6 @@ export class Frontend extends EventEmitter {
1246
975
  this.wssSendRefreshRequired('plugins');
1247
976
  this.wssSendRefreshRequired('devices');
1248
977
  }
1249
- // Uninstall the package
1250
978
  this.wssSendSnackbarMessage(`Uninstalling package ${data.params.packageName}...`, 0);
1251
979
  const { spawnCommand } = await import('./utils/spawn.js');
1252
980
  spawnCommand(this.matterbridge, 'npm', ['uninstall', '-g', data.params.packageName, '--verbose'])
@@ -1287,7 +1015,6 @@ export class Frontend extends EventEmitter {
1287
1015
  return;
1288
1016
  })
1289
1017
  .catch((_error) => {
1290
- //
1291
1018
  });
1292
1019
  }
1293
1020
  else {
@@ -1334,7 +1061,6 @@ export class Frontend extends EventEmitter {
1334
1061
  return;
1335
1062
  })
1336
1063
  .catch((_error) => {
1337
- //
1338
1064
  });
1339
1065
  }
1340
1066
  client.send(JSON.stringify({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, success: true }));
@@ -1445,8 +1171,6 @@ export class Frontend extends EventEmitter {
1445
1171
  else if (data.method === '/api/advertise') {
1446
1172
  const pairingCodes = await this.matterbridge.advertiseServerNode(this.matterbridge.serverNode);
1447
1173
  this.matterbridge.matterbridgeInformation.matterbridgeAdvertise = true;
1448
- // this.matterbridge.matterbridgeQrPairingCode = pairingCodes?.qrPairingCode;
1449
- // this.matterbridge.matterbridgeManualPairingCode = pairingCodes?.manualPairingCode;
1450
1174
  this.wssSendRefreshRequired('matterbridgeAdvertise');
1451
1175
  this.wssSendSnackbarMessage(`Started fabrics share`, 0);
1452
1176
  client.send(JSON.stringify({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, response: pairingCodes, success: true }));
@@ -1569,22 +1293,22 @@ export class Frontend extends EventEmitter {
1569
1293
  if (isValidString(data.params.value, 4)) {
1570
1294
  this.log.debug('Matterbridge logger level:', data.params.value);
1571
1295
  if (data.params.value === 'Debug') {
1572
- await this.matterbridge.setLogLevel("debug" /* LogLevel.DEBUG */);
1296
+ await this.matterbridge.setLogLevel("debug");
1573
1297
  }
1574
1298
  else if (data.params.value === 'Info') {
1575
- await this.matterbridge.setLogLevel("info" /* LogLevel.INFO */);
1299
+ await this.matterbridge.setLogLevel("info");
1576
1300
  }
1577
1301
  else if (data.params.value === 'Notice') {
1578
- await this.matterbridge.setLogLevel("notice" /* LogLevel.NOTICE */);
1302
+ await this.matterbridge.setLogLevel("notice");
1579
1303
  }
1580
1304
  else if (data.params.value === 'Warn') {
1581
- await this.matterbridge.setLogLevel("warn" /* LogLevel.WARN */);
1305
+ await this.matterbridge.setLogLevel("warn");
1582
1306
  }
1583
1307
  else if (data.params.value === 'Error') {
1584
- await this.matterbridge.setLogLevel("error" /* LogLevel.ERROR */);
1308
+ await this.matterbridge.setLogLevel("error");
1585
1309
  }
1586
1310
  else if (data.params.value === 'Fatal') {
1587
- await this.matterbridge.setLogLevel("fatal" /* LogLevel.FATAL */);
1311
+ await this.matterbridge.setLogLevel("fatal");
1588
1312
  }
1589
1313
  await this.matterbridge.nodeContext?.set('matterbridgeLogLevel', this.log.logLevel);
1590
1314
  client.send(JSON.stringify({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, success: true }));
@@ -1595,7 +1319,6 @@ export class Frontend extends EventEmitter {
1595
1319
  this.log.debug('Matterbridge file log:', data.params.value);
1596
1320
  this.matterbridge.matterbridgeInformation.fileLogger = data.params.value;
1597
1321
  await this.matterbridge.nodeContext?.set('matterbridgeFileLog', data.params.value);
1598
- // Create the file logger for matterbridge
1599
1322
  if (data.params.value)
1600
1323
  AnsiLogger.setGlobalLogfile(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterbridgeLoggerFile), this.matterbridge.matterbridgeInformation.loggerLevel, true);
1601
1324
  else
@@ -1642,7 +1365,6 @@ export class Frontend extends EventEmitter {
1642
1365
  });
1643
1366
  }
1644
1367
  catch (error) {
1645
- /* istanbul ignore next */
1646
1368
  this.log.debug(`Error adding the matterfilelogger for file ${CYAN}${path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterLoggerFile)}${er}: ${error instanceof Error ? error.message : error}`);
1647
1369
  }
1648
1370
  }
@@ -1651,7 +1373,6 @@ export class Frontend extends EventEmitter {
1651
1373
  Logger.removeLogger('matterfilelogger');
1652
1374
  }
1653
1375
  catch (error) {
1654
- /* istanbul ignore next */
1655
1376
  this.log.debug(`Error removing the matterfilelogger for file ${CYAN}${path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterLoggerFile)}${er}: ${error instanceof Error ? error.message : error}`);
1656
1377
  }
1657
1378
  }
@@ -1764,19 +1485,15 @@ export class Frontend extends EventEmitter {
1764
1485
  return;
1765
1486
  }
1766
1487
  const config = plugin.configJson;
1767
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1768
1488
  const select = plugin.schemaJson?.properties?.blackList?.selectFrom;
1769
- // this.log.debug(`SelectDevice(selectMode ${select}) data ${debugStringify(data)}`);
1770
1489
  if (select === 'serial')
1771
1490
  this.log.info(`Selected device serial ${data.params.serial}`);
1772
1491
  if (select === 'name')
1773
1492
  this.log.info(`Selected device name ${data.params.name}`);
1774
1493
  if (config && select && (select === 'serial' || select === 'name')) {
1775
- // Remove postfix from the serial if it exists
1776
1494
  if (config.postfix) {
1777
1495
  data.params.serial = data.params.serial.replace('-' + config.postfix, '');
1778
1496
  }
1779
- // Add the serial to the whiteList if the whiteList exists and the serial or name is not already in it
1780
1497
  if (isValidArray(config.whiteList, 1)) {
1781
1498
  if (select === 'serial' && !config.whiteList.includes(data.params.serial)) {
1782
1499
  config.whiteList.push(data.params.serial);
@@ -1785,7 +1502,6 @@ export class Frontend extends EventEmitter {
1785
1502
  config.whiteList.push(data.params.name);
1786
1503
  }
1787
1504
  }
1788
- // Remove the serial from the blackList if the blackList exists and the serial or name is in it
1789
1505
  if (isValidArray(config.blackList, 1)) {
1790
1506
  if (select === 'serial' && config.blackList.includes(data.params.serial)) {
1791
1507
  config.blackList = config.blackList.filter((item) => item !== data.params.serial);
@@ -1816,9 +1532,7 @@ export class Frontend extends EventEmitter {
1816
1532
  return;
1817
1533
  }
1818
1534
  const config = plugin.configJson;
1819
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1820
1535
  const select = plugin.schemaJson?.properties?.blackList?.selectFrom;
1821
- // this.log.debug(`UnselectDevice(selectMode ${select}) data ${debugStringify(data)}`);
1822
1536
  if (select === 'serial')
1823
1537
  this.log.info(`Unselected device serial ${data.params.serial}`);
1824
1538
  if (select === 'name')
@@ -1827,7 +1541,6 @@ export class Frontend extends EventEmitter {
1827
1541
  if (config.postfix) {
1828
1542
  data.params.serial = data.params.serial.replace('-' + config.postfix, '');
1829
1543
  }
1830
- // Remove the serial from the whiteList if the whiteList exists and the serial is in it
1831
1544
  if (isValidArray(config.whiteList, 1)) {
1832
1545
  if (select === 'serial' && config.whiteList.includes(data.params.serial)) {
1833
1546
  config.whiteList = config.whiteList.filter((item) => item !== data.params.serial);
@@ -1836,7 +1549,6 @@ export class Frontend extends EventEmitter {
1836
1549
  config.whiteList = config.whiteList.filter((item) => item !== data.params.name);
1837
1550
  }
1838
1551
  }
1839
- // Add the serial to the blackList
1840
1552
  if (isValidArray(config.blackList)) {
1841
1553
  if (select === 'serial' && !config.blackList.includes(data.params.serial)) {
1842
1554
  config.blackList.push(data.params.serial);
@@ -1870,230 +1582,114 @@ export class Frontend extends EventEmitter {
1870
1582
  this.log.error(`Error parsing message "${message}" from websocket client:`, error instanceof Error ? error.message : error);
1871
1583
  }
1872
1584
  }
1873
- /**
1874
- * Sends a WebSocket log message to all connected clients. The function is called by AnsiLogger.setGlobalCallback.
1875
- *
1876
- * @param {string} level - The logger level of the message: debug info notice warn error fatal...
1877
- * @param {string} time - The time string of the message
1878
- * @param {string} name - The logger name of the message
1879
- * @param {string} message - The content of the message.
1880
- *
1881
- * @remarks
1882
- * The function removes ANSI escape codes, leading asterisks, non-printable characters, and replaces all occurrences of \t and \n.
1883
- * It also replaces all occurrences of \" with " and angle-brackets with &lt; and &gt;.
1884
- * The function sends the message to all connected clients.
1885
- */
1886
1585
  wssSendMessage(level, time, name, message) {
1887
1586
  if (!level || !time || !name || !message)
1888
1587
  return;
1889
- // Remove ANSI escape codes from the message
1890
- // eslint-disable-next-line no-control-regex
1891
1588
  message = message.replace(/\x1B\[[0-9;]*[m|s|u|K]/g, '');
1892
- // Remove leading asterisks from the message
1893
1589
  message = message.replace(/^\*+/, '');
1894
- // Replace all occurrences of \t and \n
1895
1590
  message = message.replace(/[\t\n]/g, '');
1896
- // Remove non-printable characters
1897
- // eslint-disable-next-line no-control-regex
1898
1591
  message = message.replace(/[\x00-\x1F\x7F]/g, '');
1899
- // Replace all occurrences of \" with "
1900
1592
  message = message.replace(/\\"/g, '"');
1901
- // Replace all occurrences of angle-brackets with &lt; and &gt;"
1902
1593
  message = message.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
1903
- // Define the maximum allowed length for continuous characters without a space
1904
1594
  const maxContinuousLength = 100;
1905
1595
  const keepStartLength = 20;
1906
1596
  const keepEndLength = 20;
1907
- // Split the message into words
1908
1597
  message = message
1909
1598
  .split(' ')
1910
1599
  .map((word) => {
1911
- // If the word length exceeds the max continuous length, insert spaces and truncate
1912
1600
  if (word.length > maxContinuousLength) {
1913
1601
  return word.slice(0, keepStartLength) + ' ... ' + word.slice(-keepEndLength);
1914
1602
  }
1915
1603
  return word;
1916
1604
  })
1917
1605
  .join(' ');
1918
- // Send the message to all connected clients
1919
1606
  this.webSocketServer?.clients.forEach((client) => {
1920
1607
  if (client.readyState === WebSocket.OPEN) {
1921
1608
  client.send(JSON.stringify({ id: WS_ID_LOG, src: 'Matterbridge', level, time, name, message }));
1922
1609
  }
1923
1610
  });
1924
1611
  }
1925
- /**
1926
- * Sends a need to refresh WebSocket message to all connected clients.
1927
- *
1928
- * @param {string} changed - The changed value. If null, the whole page will be refreshed.
1929
- * possible values:
1930
- * - 'matterbridgeLatestVersion'
1931
- * - 'matterbridgeAdvertise'
1932
- * - 'online'
1933
- * - 'offline'
1934
- * - 'reachability'
1935
- * - 'settings'
1936
- * - 'plugins'
1937
- * - 'pluginsRestart'
1938
- * - 'devices'
1939
- * - 'fabrics'
1940
- * - 'sessions'
1941
- */
1942
1612
  wssSendRefreshRequired(changed = null) {
1943
1613
  this.log.debug('Sending a refresh required message to all connected clients');
1944
- // Send the message to all connected clients
1945
1614
  this.webSocketServer?.clients.forEach((client) => {
1946
1615
  if (client.readyState === WebSocket.OPEN) {
1947
1616
  client.send(JSON.stringify({ id: WS_ID_REFRESH_NEEDED, src: 'Matterbridge', dst: 'Frontend', method: 'refresh_required', params: { changed: changed } }));
1948
1617
  }
1949
1618
  });
1950
1619
  }
1951
- /**
1952
- * Sends a need to restart WebSocket message to all connected clients.
1953
- *
1954
- * @param {boolean} snackbar - If true, a snackbar message will be sent to all connected clients.
1955
- */
1956
1620
  wssSendRestartRequired(snackbar = true) {
1957
1621
  this.log.debug('Sending a restart required message to all connected clients');
1958
1622
  this.matterbridge.matterbridgeInformation.restartRequired = true;
1959
1623
  if (snackbar === true)
1960
1624
  this.wssSendSnackbarMessage(`Restart required`, 0);
1961
- // Send the message to all connected clients
1962
1625
  this.webSocketServer?.clients.forEach((client) => {
1963
1626
  if (client.readyState === WebSocket.OPEN) {
1964
1627
  client.send(JSON.stringify({ id: WS_ID_RESTART_NEEDED, src: 'Matterbridge', dst: 'Frontend', method: 'restart_required', params: {} }));
1965
1628
  }
1966
1629
  });
1967
1630
  }
1968
- /**
1969
- * Sends a need to update WebSocket message to all connected clients.
1970
- *
1971
- */
1972
1631
  wssSendUpdateRequired() {
1973
1632
  this.log.debug('Sending an update required message to all connected clients');
1974
1633
  this.matterbridge.matterbridgeInformation.updateRequired = true;
1975
- // Send the message to all connected clients
1976
1634
  this.webSocketServer?.clients.forEach((client) => {
1977
1635
  if (client.readyState === WebSocket.OPEN) {
1978
1636
  client.send(JSON.stringify({ id: WS_ID_UPDATE_NEEDED, src: 'Matterbridge', dst: 'Frontend', method: 'update_required', params: {} }));
1979
1637
  }
1980
1638
  });
1981
1639
  }
1982
- /**
1983
- * Sends a cpu update message to all connected clients.
1984
- *
1985
- * @param {number} cpuUsage - The CPU usage percentage to send.
1986
- */
1987
1640
  wssSendCpuUpdate(cpuUsage) {
1988
1641
  if (hasParameter('debug'))
1989
1642
  this.log.debug('Sending a cpu update message to all connected clients');
1990
- // Send the message to all connected clients
1991
1643
  this.webSocketServer?.clients.forEach((client) => {
1992
1644
  if (client.readyState === WebSocket.OPEN) {
1993
1645
  client.send(JSON.stringify({ id: WS_ID_CPU_UPDATE, src: 'Matterbridge', dst: 'Frontend', method: 'cpu_update', params: { cpuUsage } }));
1994
1646
  }
1995
1647
  });
1996
1648
  }
1997
- /**
1998
- * Sends a memory update message to all connected clients.
1999
- *
2000
- * @param {string} totalMemory - The total memory in bytes.
2001
- * @param {string} freeMemory - The free memory in bytes.
2002
- * @param {string} rss - The resident set size in bytes.
2003
- * @param {string} heapTotal - The total heap memory in bytes.
2004
- * @param {string} heapUsed - The used heap memory in bytes.
2005
- * @param {string} external - The external memory in bytes.
2006
- * @param {string} arrayBuffers - The array buffers memory in bytes.
2007
- */
2008
1649
  wssSendMemoryUpdate(totalMemory, freeMemory, rss, heapTotal, heapUsed, external, arrayBuffers) {
2009
1650
  if (hasParameter('debug'))
2010
1651
  this.log.debug('Sending a memory update message to all connected clients');
2011
- // Send the message to all connected clients
2012
1652
  this.webSocketServer?.clients.forEach((client) => {
2013
1653
  if (client.readyState === WebSocket.OPEN) {
2014
1654
  client.send(JSON.stringify({ id: WS_ID_MEMORY_UPDATE, src: 'Matterbridge', dst: 'Frontend', method: 'memory_update', params: { totalMemory, freeMemory, rss, heapTotal, heapUsed, external, arrayBuffers } }));
2015
1655
  }
2016
1656
  });
2017
1657
  }
2018
- /**
2019
- * Sends an uptime update message to all connected clients.
2020
- *
2021
- * @param {string} systemUptime - The system uptime in a human-readable format.
2022
- * @param {string} processUptime - The process uptime in a human-readable format.
2023
- */
2024
1658
  wssSendUptimeUpdate(systemUptime, processUptime) {
2025
1659
  if (hasParameter('debug'))
2026
1660
  this.log.debug('Sending a uptime update message to all connected clients');
2027
- // Send the message to all connected clients
2028
1661
  this.webSocketServer?.clients.forEach((client) => {
2029
1662
  if (client.readyState === WebSocket.OPEN) {
2030
1663
  client.send(JSON.stringify({ id: WS_ID_UPTIME_UPDATE, src: 'Matterbridge', dst: 'Frontend', method: 'uptime_update', params: { systemUptime, processUptime } }));
2031
1664
  }
2032
1665
  });
2033
1666
  }
2034
- /**
2035
- * Sends an open snackbar message to all connected clients.
2036
- *
2037
- * @param {string} message - The message to send.
2038
- * @param {number} timeout - The timeout in seconds for the snackbar message.
2039
- * @param {'info' | 'warning' | 'error' | 'success'} severity - The severity of the snackbar message (default info).
2040
- */
2041
1667
  wssSendSnackbarMessage(message, timeout = 5, severity = 'info') {
2042
1668
  this.log.debug('Sending a snackbar message to all connected clients');
2043
- // Send the message to all connected clients
2044
1669
  this.webSocketServer?.clients.forEach((client) => {
2045
1670
  if (client.readyState === WebSocket.OPEN) {
2046
1671
  client.send(JSON.stringify({ id: WS_ID_SNACKBAR, src: 'Matterbridge', dst: 'Frontend', params: { message, timeout, severity } }));
2047
1672
  }
2048
1673
  });
2049
1674
  }
2050
- /**
2051
- * Sends a close snackbar message to all connected clients.
2052
- *
2053
- * @param {string} message - The message to send.
2054
- */
2055
1675
  wssSendCloseSnackbarMessage(message) {
2056
1676
  this.log.debug('Sending a close snackbar message to all connected clients');
2057
- // Send the message to all connected clients
2058
1677
  this.webSocketServer?.clients.forEach((client) => {
2059
1678
  if (client.readyState === WebSocket.OPEN) {
2060
1679
  client.send(JSON.stringify({ id: WS_ID_CLOSE_SNACKBAR, src: 'Matterbridge', dst: 'Frontend', params: { message } }));
2061
1680
  }
2062
1681
  });
2063
1682
  }
2064
- /**
2065
- * Sends an attribute update message to all connected WebSocket clients.
2066
- *
2067
- * @param {string | undefined} plugin - The name of the plugin.
2068
- * @param {string | undefined} serialNumber - The serial number of the device.
2069
- * @param {string | undefined} uniqueId - The unique identifier of the device.
2070
- * @param {string} cluster - The cluster name where the attribute belongs.
2071
- * @param {string} attribute - The name of the attribute that changed.
2072
- * @param {number | string | boolean} value - The new value of the attribute.
2073
- *
2074
- * @remarks
2075
- * This method logs a debug message and sends a JSON-formatted message to all connected WebSocket clients
2076
- * with the updated attribute information.
2077
- */
2078
1683
  wssSendAttributeChangedMessage(plugin, serialNumber, uniqueId, cluster, attribute, value) {
2079
1684
  this.log.debug('Sending an attribute update message to all connected clients');
2080
- // Send the message to all connected clients
2081
1685
  this.webSocketServer?.clients.forEach((client) => {
2082
1686
  if (client.readyState === WebSocket.OPEN) {
2083
1687
  client.send(JSON.stringify({ id: WS_ID_STATEUPDATE, src: 'Matterbridge', dst: 'Frontend', method: 'state_update', params: { plugin, serialNumber, uniqueId, cluster, attribute, value } }));
2084
1688
  }
2085
1689
  });
2086
1690
  }
2087
- /**
2088
- * Sends a message to all connected clients.
2089
- *
2090
- * @param {number} id - The message id.
2091
- * @param {string} method - The message method.
2092
- * @param {Record<string, string | number | boolean>} params - The message parameters.
2093
- */
2094
1691
  wssBroadcastMessage(id, method, params) {
2095
1692
  this.log.debug(`Sending a broadcast message id ${id} method ${method} params ${debugStringify(params ?? {})} to all connected clients`);
2096
- // Send the message to all connected clients
2097
1693
  this.webSocketServer?.clients.forEach((client) => {
2098
1694
  if (client.readyState === WebSocket.OPEN) {
2099
1695
  client.send(JSON.stringify({ id, src: 'Matterbridge', dst: 'Frontend', method, params }));
@@ -2101,4 +1697,3 @@ export class Frontend extends EventEmitter {
2101
1697
  });
2102
1698
  }
2103
1699
  }
2104
- //# sourceMappingURL=frontend.js.map