matterbridge 3.3.2 → 3.3.3-dev-20251012-feda0f1

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 (291) hide show
  1. package/CHANGELOG.md +21 -7
  2. package/dist/broadcastServer.js +1 -86
  3. package/dist/broadcastServerTypes.js +0 -24
  4. package/dist/cli.js +5 -135
  5. package/dist/cliEmitter.js +0 -37
  6. package/dist/cliHistory.js +0 -44
  7. package/dist/clusters/export.js +0 -2
  8. package/dist/defaultConfigSchema.js +0 -24
  9. package/dist/deviceManager.js +1 -124
  10. package/dist/devices/airConditioner.js +0 -57
  11. package/dist/devices/batteryStorage.js +1 -48
  12. package/dist/devices/cooktop.js +0 -55
  13. package/dist/devices/dishwasher.js +0 -57
  14. package/dist/devices/evse.js +10 -74
  15. package/dist/devices/export.js +0 -5
  16. package/dist/devices/extractorHood.js +0 -42
  17. package/dist/devices/heatPump.js +2 -50
  18. package/dist/devices/laundryDryer.js +3 -62
  19. package/dist/devices/laundryWasher.js +4 -70
  20. package/dist/devices/microwaveOven.js +5 -88
  21. package/dist/devices/oven.js +0 -85
  22. package/dist/devices/refrigerator.js +0 -102
  23. package/dist/devices/roboticVacuumCleaner.js +9 -100
  24. package/dist/devices/solarPower.js +0 -38
  25. package/dist/devices/speaker.js +0 -84
  26. package/dist/devices/temperatureControl.js +3 -25
  27. package/dist/devices/waterHeater.js +2 -82
  28. package/dist/dgram/coap.js +13 -126
  29. package/dist/dgram/dgram.js +2 -114
  30. package/dist/dgram/mb_coap.js +3 -41
  31. package/dist/dgram/mb_mdns.js +15 -80
  32. package/dist/dgram/mdns.js +137 -299
  33. package/dist/dgram/multicast.js +1 -62
  34. package/dist/dgram/unicast.js +0 -54
  35. package/dist/frontend.js +29 -402
  36. package/dist/frontendTypes.js +0 -45
  37. package/dist/helpers.js +0 -53
  38. package/dist/index.js +0 -25
  39. package/dist/logger/export.js +0 -1
  40. package/dist/matter/behaviors.js +0 -2
  41. package/dist/matter/clusters.js +0 -2
  42. package/dist/matter/devices.js +0 -2
  43. package/dist/matter/endpoints.js +0 -2
  44. package/dist/matter/export.js +0 -3
  45. package/dist/matter/types.js +0 -3
  46. package/dist/matterbridge.js +45 -795
  47. package/dist/matterbridgeAccessoryPlatform.js +0 -36
  48. package/dist/matterbridgeBehaviors.js +5 -65
  49. package/dist/matterbridgeDeviceTypes.js +17 -630
  50. package/dist/matterbridgeDynamicPlatform.js +0 -36
  51. package/dist/matterbridgeEndpoint.js +58 -1398
  52. package/dist/matterbridgeEndpointHelpers.js +12 -345
  53. package/dist/matterbridgePlatform.js +1 -341
  54. package/dist/matterbridgeTypes.js +0 -26
  55. package/dist/pluginManager.js +3 -325
  56. package/dist/shelly.js +7 -168
  57. package/dist/storage/export.js +0 -1
  58. package/dist/update.js +0 -69
  59. package/dist/utils/colorUtils.js +2 -97
  60. package/dist/utils/commandLine.js +0 -54
  61. package/dist/utils/copyDirectory.js +1 -38
  62. package/dist/utils/createDirectory.js +0 -33
  63. package/dist/utils/createZip.js +2 -47
  64. package/dist/utils/deepCopy.js +0 -39
  65. package/dist/utils/deepEqual.js +1 -72
  66. package/dist/utils/error.js +0 -41
  67. package/dist/utils/export.js +0 -1
  68. package/dist/utils/hex.js +0 -124
  69. package/dist/utils/isvalid.js +0 -101
  70. package/dist/utils/jestHelpers.js +3 -153
  71. package/dist/utils/network.js +5 -108
  72. package/dist/utils/spawn.js +0 -71
  73. package/dist/utils/wait.js +8 -60
  74. package/npm-shrinkwrap.json +2 -2
  75. package/package.json +1 -2
  76. package/dist/broadcastServer.d.ts +0 -105
  77. package/dist/broadcastServer.d.ts.map +0 -1
  78. package/dist/broadcastServer.js.map +0 -1
  79. package/dist/broadcastServerTypes.d.ts +0 -717
  80. package/dist/broadcastServerTypes.d.ts.map +0 -1
  81. package/dist/broadcastServerTypes.js.map +0 -1
  82. package/dist/cli.d.ts +0 -26
  83. package/dist/cli.d.ts.map +0 -1
  84. package/dist/cli.js.map +0 -1
  85. package/dist/cliEmitter.d.ts +0 -50
  86. package/dist/cliEmitter.d.ts.map +0 -1
  87. package/dist/cliEmitter.js.map +0 -1
  88. package/dist/cliHistory.d.ts +0 -70
  89. package/dist/cliHistory.d.ts.map +0 -1
  90. package/dist/cliHistory.js.map +0 -1
  91. package/dist/clusters/export.d.ts +0 -2
  92. package/dist/clusters/export.d.ts.map +0 -1
  93. package/dist/clusters/export.js.map +0 -1
  94. package/dist/defaultConfigSchema.d.ts +0 -28
  95. package/dist/defaultConfigSchema.d.ts.map +0 -1
  96. package/dist/defaultConfigSchema.js.map +0 -1
  97. package/dist/deviceManager.d.ts +0 -117
  98. package/dist/deviceManager.d.ts.map +0 -1
  99. package/dist/deviceManager.js.map +0 -1
  100. package/dist/devices/airConditioner.d.ts +0 -98
  101. package/dist/devices/airConditioner.d.ts.map +0 -1
  102. package/dist/devices/airConditioner.js.map +0 -1
  103. package/dist/devices/batteryStorage.d.ts +0 -48
  104. package/dist/devices/batteryStorage.d.ts.map +0 -1
  105. package/dist/devices/batteryStorage.js.map +0 -1
  106. package/dist/devices/cooktop.d.ts +0 -60
  107. package/dist/devices/cooktop.d.ts.map +0 -1
  108. package/dist/devices/cooktop.js.map +0 -1
  109. package/dist/devices/dishwasher.d.ts +0 -71
  110. package/dist/devices/dishwasher.d.ts.map +0 -1
  111. package/dist/devices/dishwasher.js.map +0 -1
  112. package/dist/devices/evse.d.ts +0 -75
  113. package/dist/devices/evse.d.ts.map +0 -1
  114. package/dist/devices/evse.js.map +0 -1
  115. package/dist/devices/export.d.ts +0 -17
  116. package/dist/devices/export.d.ts.map +0 -1
  117. package/dist/devices/export.js.map +0 -1
  118. package/dist/devices/extractorHood.d.ts +0 -46
  119. package/dist/devices/extractorHood.d.ts.map +0 -1
  120. package/dist/devices/extractorHood.js.map +0 -1
  121. package/dist/devices/heatPump.d.ts +0 -47
  122. package/dist/devices/heatPump.d.ts.map +0 -1
  123. package/dist/devices/heatPump.js.map +0 -1
  124. package/dist/devices/laundryDryer.d.ts +0 -67
  125. package/dist/devices/laundryDryer.d.ts.map +0 -1
  126. package/dist/devices/laundryDryer.js.map +0 -1
  127. package/dist/devices/laundryWasher.d.ts +0 -81
  128. package/dist/devices/laundryWasher.d.ts.map +0 -1
  129. package/dist/devices/laundryWasher.js.map +0 -1
  130. package/dist/devices/microwaveOven.d.ts +0 -168
  131. package/dist/devices/microwaveOven.d.ts.map +0 -1
  132. package/dist/devices/microwaveOven.js.map +0 -1
  133. package/dist/devices/oven.d.ts +0 -105
  134. package/dist/devices/oven.d.ts.map +0 -1
  135. package/dist/devices/oven.js.map +0 -1
  136. package/dist/devices/refrigerator.d.ts +0 -118
  137. package/dist/devices/refrigerator.d.ts.map +0 -1
  138. package/dist/devices/refrigerator.js.map +0 -1
  139. package/dist/devices/roboticVacuumCleaner.d.ts +0 -112
  140. package/dist/devices/roboticVacuumCleaner.d.ts.map +0 -1
  141. package/dist/devices/roboticVacuumCleaner.js.map +0 -1
  142. package/dist/devices/solarPower.d.ts +0 -40
  143. package/dist/devices/solarPower.d.ts.map +0 -1
  144. package/dist/devices/solarPower.js.map +0 -1
  145. package/dist/devices/speaker.d.ts +0 -87
  146. package/dist/devices/speaker.d.ts.map +0 -1
  147. package/dist/devices/speaker.js.map +0 -1
  148. package/dist/devices/temperatureControl.d.ts +0 -166
  149. package/dist/devices/temperatureControl.d.ts.map +0 -1
  150. package/dist/devices/temperatureControl.js.map +0 -1
  151. package/dist/devices/waterHeater.d.ts +0 -111
  152. package/dist/devices/waterHeater.d.ts.map +0 -1
  153. package/dist/devices/waterHeater.js.map +0 -1
  154. package/dist/dgram/coap.d.ts +0 -205
  155. package/dist/dgram/coap.d.ts.map +0 -1
  156. package/dist/dgram/coap.js.map +0 -1
  157. package/dist/dgram/dgram.d.ts +0 -141
  158. package/dist/dgram/dgram.d.ts.map +0 -1
  159. package/dist/dgram/dgram.js.map +0 -1
  160. package/dist/dgram/mb_coap.d.ts +0 -24
  161. package/dist/dgram/mb_coap.d.ts.map +0 -1
  162. package/dist/dgram/mb_coap.js.map +0 -1
  163. package/dist/dgram/mb_mdns.d.ts +0 -24
  164. package/dist/dgram/mb_mdns.d.ts.map +0 -1
  165. package/dist/dgram/mb_mdns.js.map +0 -1
  166. package/dist/dgram/mdns.d.ts +0 -290
  167. package/dist/dgram/mdns.d.ts.map +0 -1
  168. package/dist/dgram/mdns.js.map +0 -1
  169. package/dist/dgram/multicast.d.ts +0 -67
  170. package/dist/dgram/multicast.d.ts.map +0 -1
  171. package/dist/dgram/multicast.js.map +0 -1
  172. package/dist/dgram/unicast.d.ts +0 -56
  173. package/dist/dgram/unicast.d.ts.map +0 -1
  174. package/dist/dgram/unicast.js.map +0 -1
  175. package/dist/frontend.d.ts +0 -234
  176. package/dist/frontend.d.ts.map +0 -1
  177. package/dist/frontend.js.map +0 -1
  178. package/dist/frontendTypes.d.ts +0 -522
  179. package/dist/frontendTypes.d.ts.map +0 -1
  180. package/dist/frontendTypes.js.map +0 -1
  181. package/dist/helpers.d.ts +0 -48
  182. package/dist/helpers.d.ts.map +0 -1
  183. package/dist/helpers.js.map +0 -1
  184. package/dist/index.d.ts +0 -33
  185. package/dist/index.d.ts.map +0 -1
  186. package/dist/index.js.map +0 -1
  187. package/dist/logger/export.d.ts +0 -2
  188. package/dist/logger/export.d.ts.map +0 -1
  189. package/dist/logger/export.js.map +0 -1
  190. package/dist/matter/behaviors.d.ts +0 -2
  191. package/dist/matter/behaviors.d.ts.map +0 -1
  192. package/dist/matter/behaviors.js.map +0 -1
  193. package/dist/matter/clusters.d.ts +0 -2
  194. package/dist/matter/clusters.d.ts.map +0 -1
  195. package/dist/matter/clusters.js.map +0 -1
  196. package/dist/matter/devices.d.ts +0 -2
  197. package/dist/matter/devices.d.ts.map +0 -1
  198. package/dist/matter/devices.js.map +0 -1
  199. package/dist/matter/endpoints.d.ts +0 -2
  200. package/dist/matter/endpoints.d.ts.map +0 -1
  201. package/dist/matter/endpoints.js.map +0 -1
  202. package/dist/matter/export.d.ts +0 -5
  203. package/dist/matter/export.d.ts.map +0 -1
  204. package/dist/matter/export.js.map +0 -1
  205. package/dist/matter/types.d.ts +0 -3
  206. package/dist/matter/types.d.ts.map +0 -1
  207. package/dist/matter/types.js.map +0 -1
  208. package/dist/matterbridge.d.ts +0 -469
  209. package/dist/matterbridge.d.ts.map +0 -1
  210. package/dist/matterbridge.js.map +0 -1
  211. package/dist/matterbridgeAccessoryPlatform.d.ts +0 -42
  212. package/dist/matterbridgeAccessoryPlatform.d.ts.map +0 -1
  213. package/dist/matterbridgeAccessoryPlatform.js.map +0 -1
  214. package/dist/matterbridgeBehaviors.d.ts +0 -1747
  215. package/dist/matterbridgeBehaviors.d.ts.map +0 -1
  216. package/dist/matterbridgeBehaviors.js.map +0 -1
  217. package/dist/matterbridgeDeviceTypes.d.ts +0 -761
  218. package/dist/matterbridgeDeviceTypes.d.ts.map +0 -1
  219. package/dist/matterbridgeDeviceTypes.js.map +0 -1
  220. package/dist/matterbridgeDynamicPlatform.d.ts +0 -42
  221. package/dist/matterbridgeDynamicPlatform.d.ts.map +0 -1
  222. package/dist/matterbridgeDynamicPlatform.js.map +0 -1
  223. package/dist/matterbridgeEndpoint.d.ts +0 -1534
  224. package/dist/matterbridgeEndpoint.d.ts.map +0 -1
  225. package/dist/matterbridgeEndpoint.js.map +0 -1
  226. package/dist/matterbridgeEndpointHelpers.d.ts +0 -407
  227. package/dist/matterbridgeEndpointHelpers.d.ts.map +0 -1
  228. package/dist/matterbridgeEndpointHelpers.js.map +0 -1
  229. package/dist/matterbridgePlatform.d.ts +0 -402
  230. package/dist/matterbridgePlatform.d.ts.map +0 -1
  231. package/dist/matterbridgePlatform.js.map +0 -1
  232. package/dist/matterbridgeTypes.d.ts +0 -209
  233. package/dist/matterbridgeTypes.d.ts.map +0 -1
  234. package/dist/matterbridgeTypes.js.map +0 -1
  235. package/dist/pluginManager.d.ts +0 -353
  236. package/dist/pluginManager.d.ts.map +0 -1
  237. package/dist/pluginManager.js.map +0 -1
  238. package/dist/shelly.d.ts +0 -174
  239. package/dist/shelly.d.ts.map +0 -1
  240. package/dist/shelly.js.map +0 -1
  241. package/dist/storage/export.d.ts +0 -2
  242. package/dist/storage/export.d.ts.map +0 -1
  243. package/dist/storage/export.js.map +0 -1
  244. package/dist/update.d.ts +0 -75
  245. package/dist/update.d.ts.map +0 -1
  246. package/dist/update.js.map +0 -1
  247. package/dist/utils/colorUtils.d.ts +0 -99
  248. package/dist/utils/colorUtils.d.ts.map +0 -1
  249. package/dist/utils/colorUtils.js.map +0 -1
  250. package/dist/utils/commandLine.d.ts +0 -59
  251. package/dist/utils/commandLine.d.ts.map +0 -1
  252. package/dist/utils/commandLine.js.map +0 -1
  253. package/dist/utils/copyDirectory.d.ts +0 -33
  254. package/dist/utils/copyDirectory.d.ts.map +0 -1
  255. package/dist/utils/copyDirectory.js.map +0 -1
  256. package/dist/utils/createDirectory.d.ts +0 -34
  257. package/dist/utils/createDirectory.d.ts.map +0 -1
  258. package/dist/utils/createDirectory.js.map +0 -1
  259. package/dist/utils/createZip.d.ts +0 -39
  260. package/dist/utils/createZip.d.ts.map +0 -1
  261. package/dist/utils/createZip.js.map +0 -1
  262. package/dist/utils/deepCopy.d.ts +0 -32
  263. package/dist/utils/deepCopy.d.ts.map +0 -1
  264. package/dist/utils/deepCopy.js.map +0 -1
  265. package/dist/utils/deepEqual.d.ts +0 -54
  266. package/dist/utils/deepEqual.d.ts.map +0 -1
  267. package/dist/utils/deepEqual.js.map +0 -1
  268. package/dist/utils/error.d.ts +0 -44
  269. package/dist/utils/error.d.ts.map +0 -1
  270. package/dist/utils/error.js.map +0 -1
  271. package/dist/utils/export.d.ts +0 -13
  272. package/dist/utils/export.d.ts.map +0 -1
  273. package/dist/utils/export.js.map +0 -1
  274. package/dist/utils/hex.d.ts +0 -89
  275. package/dist/utils/hex.d.ts.map +0 -1
  276. package/dist/utils/hex.js.map +0 -1
  277. package/dist/utils/isvalid.d.ts +0 -103
  278. package/dist/utils/isvalid.d.ts.map +0 -1
  279. package/dist/utils/isvalid.js.map +0 -1
  280. package/dist/utils/jestHelpers.d.ts +0 -137
  281. package/dist/utils/jestHelpers.d.ts.map +0 -1
  282. package/dist/utils/jestHelpers.js.map +0 -1
  283. package/dist/utils/network.d.ts +0 -115
  284. package/dist/utils/network.d.ts.map +0 -1
  285. package/dist/utils/network.js.map +0 -1
  286. package/dist/utils/spawn.d.ts +0 -35
  287. package/dist/utils/spawn.d.ts.map +0 -1
  288. package/dist/utils/spawn.js.map +0 -1
  289. package/dist/utils/wait.d.ts +0 -54
  290. package/dist/utils/wait.d.ts.map +0 -1
  291. package/dist/utils/wait.js.map +0 -1
package/dist/frontend.js CHANGED
@@ -1,35 +1,9 @@
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.3.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
- // eslint-disable-next-line no-console
25
1
  if (process.argv.includes('--loader') || process.argv.includes('-loader'))
26
2
  console.log('\u001B[32mFrontend loaded.\u001B[40;0m');
27
3
  import os from 'node:os';
28
4
  import path from 'node:path';
29
5
  import EventEmitter from 'node:events';
30
- // AnsiLogger module
31
6
  import { AnsiLogger, stringify, debugStringify, CYAN, db, er, nf, rs, UNDERLINE, UNDERLINEOFF, YELLOW, nt, wr } from 'node-ansi-logger';
32
- // @matter
33
7
  import { Logger, LogLevel as MatterLogLevel, LogFormat as MatterLogFormat, Lifecycle, LogDestination, Diagnostic, Time, FabricIndex } from '@matter/main';
34
8
  import { BridgedDeviceBasicInformation } from '@matter/main/clusters/bridged-device-basic-information';
35
9
  import { PowerSource } from '@matter/main/clusters/power-source';
@@ -59,7 +33,7 @@ export class Frontend extends EventEmitter {
59
33
  constructor(matterbridge) {
60
34
  super();
61
35
  this.matterbridge = matterbridge;
62
- this.log = new AnsiLogger({ logName: 'Frontend', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: hasParameter('debug') ? "debug" /* LogLevel.DEBUG */ : "info" /* LogLevel.INFO */ });
36
+ this.log = new AnsiLogger({ logName: 'Frontend', logTimestampFormat: 4, logLevel: hasParameter('debug') ? "debug" : "info" });
63
37
  this.log.logNameColor = '\x1b[38;5;97m';
64
38
  this.server = new BroadcastServer('plugins', this.log);
65
39
  this.server.on('broadcast_message', this.msgHandler.bind(this));
@@ -121,42 +95,13 @@ export class Frontend extends EventEmitter {
121
95
  async start(port = 8283) {
122
96
  this.port = port;
123
97
  this.log.debug(`Initializing the frontend ${hasParameter('ssl') ? 'https' : 'http'} server on port ${YELLOW}${this.port}${db}`);
124
- // Initialize multer with the upload directory
125
98
  const multer = await import('multer');
126
- const uploadDir = path.join(this.matterbridge.matterbridgeDirectory, 'uploads'); // Is created by matterbridge initialize
99
+ const uploadDir = path.join(this.matterbridge.matterbridgeDirectory, 'uploads');
127
100
  const upload = multer.default({ dest: uploadDir });
128
- // Create the express app that serves the frontend
129
101
  const express = await import('express');
130
102
  this.expressApp = express.default();
131
- // Inject logging/debug wrapper for route/middleware registration
132
- /*
133
- const methods = ['get', 'post', 'put', 'delete', 'use'];
134
- for (const method of methods) {
135
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
136
- const original = (this.expressApp as any)[method].bind(this.expressApp);
137
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
138
- (this.expressApp as any)[method] = (path: any, ...rest: any) => {
139
- try {
140
- console.log(`[DEBUG] Registering ${method.toUpperCase()} route:`, path);
141
- return original(path, ...rest);
142
- } catch (err) {
143
- console.error(`[ERROR] Failed to register route: ${path}`);
144
- throw err;
145
- }
146
- };
147
- }
148
- */
149
- // Log all requests to the server for debugging
150
- /*
151
- this.expressApp.use((req, res, next) => {
152
- this.log.debug(`***Received request on expressApp: ${req.method} ${req.url}`);
153
- next();
154
- });
155
- */
156
- // Serve static files from 'frontend/build' directory
157
103
  this.expressApp.use(express.static(path.join(this.matterbridge.rootDirectory, 'frontend/build')));
158
104
  if (!hasParameter('ssl')) {
159
- // Create an HTTP server and attach the express app
160
105
  const http = await import('node:http');
161
106
  try {
162
107
  this.log.debug(`Creating HTTP server...`);
@@ -167,7 +112,6 @@ export class Frontend extends EventEmitter {
167
112
  this.emit('server_error', error);
168
113
  return;
169
114
  }
170
- // Listen on the specified port
171
115
  if (hasParameter('ingress')) {
172
116
  this.httpServer.listen(this.port, '0.0.0.0', () => {
173
117
  this.log.info(`The frontend http server is listening on ${UNDERLINE}http://0.0.0.0:${this.port}${UNDERLINEOFF}${rs}`);
@@ -200,7 +144,6 @@ export class Frontend extends EventEmitter {
200
144
  });
201
145
  }
202
146
  else {
203
- // SSL is enabled, load the certificate and the private key
204
147
  let cert;
205
148
  let key;
206
149
  let ca;
@@ -210,7 +153,6 @@ export class Frontend extends EventEmitter {
210
153
  let httpsServerOptions = {};
211
154
  const fs = await import('node:fs');
212
155
  if (fs.existsSync(path.join(this.matterbridge.matterbridgeDirectory, 'certs/cert.p12'))) {
213
- // Load the p12 certificate and the passphrase
214
156
  try {
215
157
  pfx = await fs.promises.readFile(path.join(this.matterbridge.matterbridgeDirectory, 'certs/cert.p12'));
216
158
  this.log.info(`Loaded p12 certificate file ${path.join(this.matterbridge.matterbridgeDirectory, 'certs/cert.p12')}`);
@@ -222,7 +164,7 @@ export class Frontend extends EventEmitter {
222
164
  }
223
165
  try {
224
166
  passphrase = await fs.promises.readFile(path.join(this.matterbridge.matterbridgeDirectory, 'certs/cert.pass'), 'utf8');
225
- passphrase = passphrase.trim(); // Ensure no extra characters
167
+ passphrase = passphrase.trim();
226
168
  this.log.info(`Loaded p12 passphrase file ${path.join(this.matterbridge.matterbridgeDirectory, 'certs/cert.pass')}`);
227
169
  }
228
170
  catch (error) {
@@ -233,7 +175,6 @@ export class Frontend extends EventEmitter {
233
175
  httpsServerOptions = { pfx, passphrase };
234
176
  }
235
177
  else {
236
- // Load the SSL certificate, the private key and optionally the CA certificate. If the CA certificate is present, it will be used to create a full chain certificate.
237
178
  try {
238
179
  cert = await fs.promises.readFile(path.join(this.matterbridge.matterbridgeDirectory, 'certs/cert.pem'), 'utf8');
239
180
  this.log.info(`Loaded certificate file ${path.join(this.matterbridge.matterbridgeDirectory, 'certs/cert.pem')}`);
@@ -263,10 +204,9 @@ export class Frontend extends EventEmitter {
263
204
  httpsServerOptions = { cert: fullChain ?? cert, key, ca };
264
205
  }
265
206
  if (hasParameter('mtls')) {
266
- httpsServerOptions.requestCert = true; // Request client certificate
267
- httpsServerOptions.rejectUnauthorized = true; // Require client certificate validation
207
+ httpsServerOptions.requestCert = true;
208
+ httpsServerOptions.rejectUnauthorized = true;
268
209
  }
269
- // Create an HTTPS server with the SSL certificate and private key (ca is optional) and attach the express app
270
210
  const https = await import('node:https');
271
211
  try {
272
212
  this.log.debug(`Creating HTTPS server...`);
@@ -277,7 +217,6 @@ export class Frontend extends EventEmitter {
277
217
  this.emit('server_error', error);
278
218
  return;
279
219
  }
280
- // Listen on the specified port
281
220
  if (hasParameter('ingress')) {
282
221
  this.httpsServer.listen(this.port, '0.0.0.0', () => {
283
222
  this.log.info(`The frontend https server is listening on ${UNDERLINE}https://0.0.0.0:${this.port}${UNDERLINEOFF}${rs}`);
@@ -309,18 +248,16 @@ export class Frontend extends EventEmitter {
309
248
  return;
310
249
  });
311
250
  }
312
- // Create a WebSocket server and attach it to the http or https server
313
251
  const ws = await import('ws');
314
252
  this.log.debug(`Creating WebSocketServer...`);
315
253
  this.webSocketServer = new ws.WebSocketServer(hasParameter('ssl') ? { server: this.httpsServer } : { server: this.httpServer });
316
254
  this.webSocketServer.on('connection', (ws, request) => {
317
255
  const clientIp = request.socket.remoteAddress;
318
- // Set the global logger callback for the WebSocketServer
319
- let callbackLogLevel = "notice" /* LogLevel.NOTICE */;
320
- if (this.matterbridge.getLogLevel() === "info" /* LogLevel.INFO */ || Logger.level === MatterLogLevel.INFO)
321
- callbackLogLevel = "info" /* LogLevel.INFO */;
322
- if (this.matterbridge.getLogLevel() === "debug" /* LogLevel.DEBUG */ || Logger.level === MatterLogLevel.DEBUG)
323
- callbackLogLevel = "debug" /* LogLevel.DEBUG */;
256
+ let callbackLogLevel = "notice";
257
+ if (this.matterbridge.getLogLevel() === "info" || Logger.level === MatterLogLevel.INFO)
258
+ callbackLogLevel = "info";
259
+ if (this.matterbridge.getLogLevel() === "debug" || Logger.level === MatterLogLevel.DEBUG)
260
+ callbackLogLevel = "debug";
324
261
  AnsiLogger.setGlobalCallback(this.wssSendLogMessage.bind(this), callbackLogLevel);
325
262
  this.log.debug(`WebSocketServer logger global callback set to ${callbackLogLevel}`);
326
263
  this.log.info(`WebSocketServer client "${clientIp}" connected to Matterbridge`);
@@ -342,7 +279,6 @@ export class Frontend extends EventEmitter {
342
279
  }
343
280
  });
344
281
  ws.on('error', (error) => {
345
- // istanbul ignore next
346
282
  this.log.error(`WebSocket client error: ${error}`);
347
283
  });
348
284
  });
@@ -356,7 +292,6 @@ export class Frontend extends EventEmitter {
356
292
  this.webSocketServer.on('error', (ws, error) => {
357
293
  this.log.error(`WebSocketServer error: ${error}`);
358
294
  });
359
- // Subscribe to cli events
360
295
  cliEmitter.removeAllListeners();
361
296
  cliEmitter.on('uptime', (systemUptime, processUptime) => {
362
297
  this.wssSendUptimeUpdate(systemUptime, processUptime);
@@ -367,8 +302,6 @@ export class Frontend extends EventEmitter {
367
302
  cliEmitter.on('cpu', (cpuUsage, processCpuUsage) => {
368
303
  this.wssSendCpuUpdate(cpuUsage, processCpuUsage);
369
304
  });
370
- // Endpoint to validate login code
371
- // curl -X POST "http://localhost:8283/api/login" -H "Content-Type: application/json" -d "{\"password\":\"Here\"}"
372
305
  this.expressApp.post('/api/login', express.json(), async (req, res) => {
373
306
  const { password } = req.body;
374
307
  this.log.debug('The frontend sent /api/login', password);
@@ -387,27 +320,23 @@ export class Frontend extends EventEmitter {
387
320
  this.log.warn('/api/login error wrong password');
388
321
  res.json({ valid: false });
389
322
  }
390
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
391
323
  }
392
324
  catch (error) {
393
325
  this.log.error('/api/login error getting password');
394
326
  res.json({ valid: false });
395
327
  }
396
328
  });
397
- // Endpoint to provide health check for docker
398
329
  this.expressApp.get('/health', (req, res) => {
399
330
  this.log.debug('Express received /health');
400
331
  const healthStatus = {
401
- status: 'ok', // Indicate service is healthy
402
- uptime: process.uptime(), // Server uptime in seconds
403
- timestamp: new Date().toISOString(), // Current timestamp
332
+ status: 'ok',
333
+ uptime: process.uptime(),
334
+ timestamp: new Date().toISOString(),
404
335
  };
405
336
  res.status(200).json(healthStatus);
406
337
  });
407
- // Endpoint to provide memory usage details
408
338
  this.expressApp.get('/memory', async (req, res) => {
409
339
  this.log.debug('Express received /memory');
410
- // Memory usage from process
411
340
  const memoryUsageRaw = process.memoryUsage();
412
341
  const memoryUsage = {
413
342
  rss: formatMemoryUsage(memoryUsageRaw.rss),
@@ -416,13 +345,10 @@ export class Frontend extends EventEmitter {
416
345
  external: formatMemoryUsage(memoryUsageRaw.external),
417
346
  arrayBuffers: formatMemoryUsage(memoryUsageRaw.arrayBuffers),
418
347
  };
419
- // V8 heap statistics
420
348
  const { default: v8 } = await import('node:v8');
421
349
  const heapStatsRaw = v8.getHeapStatistics();
422
350
  const heapSpacesRaw = v8.getHeapSpaceStatistics();
423
- // Format heapStats
424
351
  const heapStats = Object.fromEntries(Object.entries(heapStatsRaw).map(([key, value]) => [key, formatMemoryUsage(value)]));
425
- // Format heapSpaces
426
352
  const heapSpaces = heapSpacesRaw.map((space) => ({
427
353
  ...space,
428
354
  space_size: formatMemoryUsage(space.space_size),
@@ -441,22 +367,18 @@ export class Frontend extends EventEmitter {
441
367
  };
442
368
  res.status(200).json(memoryReport);
443
369
  });
444
- // Endpoint to provide settings
445
370
  this.expressApp.get('/api/settings', express.json(), async (req, res) => {
446
371
  this.log.debug('The frontend sent /api/settings');
447
372
  res.json(await this.getApiSettings());
448
373
  });
449
- // Endpoint to provide plugins
450
374
  this.expressApp.get('/api/plugins', async (req, res) => {
451
375
  this.log.debug('The frontend sent /api/plugins');
452
376
  res.json(this.matterbridge.hasCleanupStarted ? [] : this.getPlugins());
453
377
  });
454
- // Endpoint to provide devices
455
378
  this.expressApp.get('/api/devices', async (req, res) => {
456
379
  this.log.debug('The frontend sent /api/devices');
457
380
  res.json(this.matterbridge.hasCleanupStarted ? [] : this.getDevices());
458
381
  });
459
- // Endpoint to view the matterbridge log
460
382
  this.expressApp.get('/api/view-mblog', async (req, res) => {
461
383
  this.log.debug('The frontend sent /api/view-mblog');
462
384
  try {
@@ -470,7 +392,6 @@ export class Frontend extends EventEmitter {
470
392
  res.status(500).send('Error reading matterbridge log file. Please enable the matterbridge log on file in the settings.');
471
393
  }
472
394
  });
473
- // Endpoint to view the matter.js log
474
395
  this.expressApp.get('/api/view-mjlog', async (req, res) => {
475
396
  this.log.debug('The frontend sent /api/view-mjlog');
476
397
  try {
@@ -484,11 +405,9 @@ export class Frontend extends EventEmitter {
484
405
  res.status(500).send('Error reading matter log file. Please enable the matter log on file in the settings.');
485
406
  }
486
407
  });
487
- // Endpoint to view the diagnostic.log
488
408
  this.expressApp.get('/api/view-diagnostic', async (req, res) => {
489
409
  this.log.debug('The frontend sent /api/view-diagnostic');
490
410
  const serverNodes = [];
491
- // istanbul ignore else
492
411
  if (this.matterbridge.bridgeMode === 'bridge') {
493
412
  if (this.matterbridge.serverNode)
494
413
  serverNodes.push(this.matterbridge.serverNode);
@@ -499,7 +418,6 @@ export class Frontend extends EventEmitter {
499
418
  serverNodes.push(plugin.serverNode);
500
419
  }
501
420
  }
502
- // istanbul ignore next
503
421
  for (const device of this.matterbridge.devices.array()) {
504
422
  if (device.serverNode)
505
423
  serverNodes.push(device.serverNode);
@@ -523,7 +441,7 @@ export class Frontend extends EventEmitter {
523
441
  values: [...serverNodes],
524
442
  })));
525
443
  delete Logger.destinations.diagnostic;
526
- await wait(500); // Wait for the log to be written
444
+ await wait(500);
527
445
  try {
528
446
  const fs = await import('node:fs');
529
447
  const data = await fs.promises.readFile(path.join(this.matterbridge.matterbridgeDirectory, MATTERBRIDGE_DIAGNOSTIC_FILE), 'utf8');
@@ -531,13 +449,10 @@ export class Frontend extends EventEmitter {
531
449
  res.send(data.slice(29));
532
450
  }
533
451
  catch (error) {
534
- // istanbul ignore next
535
452
  this.log.error(`Error reading diagnostic log file ${MATTERBRIDGE_DIAGNOSTIC_FILE}: ${error instanceof Error ? error.message : error}`);
536
- // istanbul ignore next
537
453
  res.status(500).send('Error reading diagnostic log file.');
538
454
  }
539
455
  });
540
- // Endpoint to view the history.html
541
456
  this.expressApp.get('/api/viewhistory', async (req, res) => {
542
457
  this.log.debug('The frontend sent /api/viewhistory');
543
458
  try {
@@ -551,7 +466,6 @@ export class Frontend extends EventEmitter {
551
466
  res.status(500).send('Error reading history log file. Please create the history log before loading it.');
552
467
  }
553
468
  });
554
- // Endpoint to view the shelly log
555
469
  this.expressApp.get('/api/shellyviewsystemlog', async (req, res) => {
556
470
  this.log.debug('The frontend sent /api/shellyviewsystemlog');
557
471
  try {
@@ -565,7 +479,6 @@ export class Frontend extends EventEmitter {
565
479
  res.status(500).send('Error reading shelly log file. Please create the shelly system log before loading it.');
566
480
  }
567
481
  });
568
- // Endpoint to download the matterbridge log
569
482
  this.expressApp.get('/api/download-mblog', async (req, res) => {
570
483
  this.log.debug(`The frontend sent /api/download-mblog ${path.join(this.matterbridge.matterbridgeDirectory, MATTERBRIDGE_LOGGER_FILE)}`);
571
484
  const fs = await import('node:fs');
@@ -580,14 +493,12 @@ export class Frontend extends EventEmitter {
580
493
  }
581
494
  res.type('text/plain');
582
495
  res.download(path.join(os.tmpdir(), MATTERBRIDGE_LOGGER_FILE), 'matterbridge.log', (error) => {
583
- /* istanbul ignore if */
584
496
  if (error) {
585
497
  this.log.error(`Error downloading log file ${MATTERBRIDGE_LOGGER_FILE}: ${error instanceof Error ? error.message : error}`);
586
498
  res.status(500).send('Error downloading the matterbridge log file');
587
499
  }
588
500
  });
589
501
  });
590
- // Endpoint to download the matter log
591
502
  this.expressApp.get('/api/download-mjlog', async (req, res) => {
592
503
  this.log.debug(`The frontend sent /api/download-mjlog ${path.join(this.matterbridge.matterbridgeDirectory, MATTERBRIDGE_LOGGER_FILE)}`);
593
504
  const fs = await import('node:fs');
@@ -602,14 +513,12 @@ export class Frontend extends EventEmitter {
602
513
  }
603
514
  res.type('text/plain');
604
515
  res.download(path.join(os.tmpdir(), MATTER_LOGGER_FILE), 'matter.log', (error) => {
605
- /* istanbul ignore if */
606
516
  if (error) {
607
517
  this.log.error(`Error downloading log file ${MATTER_LOGGER_FILE}: ${error instanceof Error ? error.message : error}`);
608
518
  res.status(500).send('Error downloading the matter log file');
609
519
  }
610
520
  });
611
521
  });
612
- // Endpoint to download the shelly log
613
522
  this.expressApp.get('/api/shellydownloadsystemlog', async (req, res) => {
614
523
  this.log.debug('The frontend sent /api/shellydownloadsystemlog');
615
524
  const fs = await import('node:fs');
@@ -624,91 +533,75 @@ export class Frontend extends EventEmitter {
624
533
  }
625
534
  res.type('text/plain');
626
535
  res.download(path.join(os.tmpdir(), 'shelly.log'), 'shelly.log', (error) => {
627
- /* istanbul ignore if */
628
536
  if (error) {
629
537
  this.log.error(`Error downloading Shelly system log file: ${error instanceof Error ? error.message : error}`);
630
538
  res.status(500).send('Error downloading Shelly system log file');
631
539
  }
632
540
  });
633
541
  });
634
- // Endpoint to download the matterbridge storage directory
635
542
  this.expressApp.get('/api/download-mbstorage', async (req, res) => {
636
543
  this.log.debug('The frontend sent /api/download-mbstorage');
637
544
  await createZip(path.join(os.tmpdir(), `matterbridge.${NODE_STORAGE_DIR}.zip`), path.join(this.matterbridge.matterbridgeDirectory, NODE_STORAGE_DIR));
638
545
  res.download(path.join(os.tmpdir(), `matterbridge.${NODE_STORAGE_DIR}.zip`), `matterbridge.${NODE_STORAGE_DIR}.zip`, (error) => {
639
- /* istanbul ignore if */
640
546
  if (error) {
641
547
  this.log.error(`Error downloading file ${`matterbridge.${NODE_STORAGE_DIR}.zip`}: ${error instanceof Error ? error.message : error}`);
642
548
  res.status(500).send('Error downloading the matterbridge storage file');
643
549
  }
644
550
  });
645
551
  });
646
- // Endpoint to download the matter storage file
647
552
  this.expressApp.get('/api/download-mjstorage', async (req, res) => {
648
553
  this.log.debug('The frontend sent /api/download-mjstorage');
649
554
  await createZip(path.join(os.tmpdir(), `matterbridge.${MATTER_STORAGE_NAME}.zip`), path.join(this.matterbridge.matterbridgeDirectory, MATTER_STORAGE_NAME));
650
555
  res.download(path.join(os.tmpdir(), `matterbridge.${MATTER_STORAGE_NAME}.zip`), `matterbridge.${MATTER_STORAGE_NAME}.zip`, (error) => {
651
- /* istanbul ignore if */
652
556
  if (error) {
653
557
  this.log.error(`Error downloading the matter storage matterbridge.${MATTER_STORAGE_NAME}.zip: ${error instanceof Error ? error.message : error}`);
654
558
  res.status(500).send('Error downloading the matter storage zip file');
655
559
  }
656
560
  });
657
561
  });
658
- // Endpoint to download the matterbridge plugin directory
659
562
  this.expressApp.get('/api/download-pluginstorage', async (req, res) => {
660
563
  this.log.debug('The frontend sent /api/download-pluginstorage');
661
564
  await createZip(path.join(os.tmpdir(), `matterbridge.pluginstorage.zip`), this.matterbridge.matterbridgePluginDirectory);
662
565
  res.download(path.join(os.tmpdir(), `matterbridge.pluginstorage.zip`), `matterbridge.pluginstorage.zip`, (error) => {
663
- /* istanbul ignore if */
664
566
  if (error) {
665
567
  this.log.error(`Error downloading file matterbridge.pluginstorage.zip: ${error instanceof Error ? error.message : error}`);
666
568
  res.status(500).send('Error downloading the matterbridge plugin storage file');
667
569
  }
668
570
  });
669
571
  });
670
- // Endpoint to download the matterbridge plugin config files
671
572
  this.expressApp.get('/api/download-pluginconfig', async (req, res) => {
672
573
  this.log.debug('The frontend sent /api/download-pluginconfig');
673
574
  await createZip(path.join(os.tmpdir(), `matterbridge.pluginconfig.zip`), path.relative(process.cwd(), path.join(this.matterbridge.matterbridgeDirectory, '*.config.json')));
674
575
  res.download(path.join(os.tmpdir(), `matterbridge.pluginconfig.zip`), `matterbridge.pluginconfig.zip`, (error) => {
675
- /* istanbul ignore if */
676
576
  if (error) {
677
577
  this.log.error(`Error downloading file matterbridge.pluginconfig.zip: ${error instanceof Error ? error.message : error}`);
678
578
  res.status(500).send('Error downloading the matterbridge plugin config file');
679
579
  }
680
580
  });
681
581
  });
682
- // Endpoint to download the matterbridge backup (created with the backup command)
683
582
  this.expressApp.get('/api/download-backup', async (req, res) => {
684
583
  this.log.debug('The frontend sent /api/download-backup');
685
584
  res.download(path.join(os.tmpdir(), `matterbridge.backup.zip`), `matterbridge.backup.zip`, (error) => {
686
- /* istanbul ignore if */
687
585
  if (error) {
688
586
  this.log.error(`Error downloading file matterbridge.backup.zip: ${error instanceof Error ? error.message : error}`);
689
587
  res.status(500).send(`Error downloading file matterbridge.backup.zip: ${error instanceof Error ? error.message : error}`);
690
588
  }
691
589
  });
692
590
  });
693
- // Endpoint to upload a package
694
591
  this.expressApp.post('/api/uploadpackage', upload.single('file'), async (req, res) => {
695
592
  const { filename } = req.body;
696
593
  const file = req.file;
697
- /* istanbul ignore if */
698
594
  if (!file || !filename) {
699
595
  this.log.error(`uploadpackage: invalid request: file and filename are required`);
700
596
  res.status(400).send('Invalid request: file and filename are required');
701
597
  return;
702
598
  }
703
599
  this.wssSendSnackbarMessage(`Installing package ${filename}. Please wait...`, 0);
704
- // Define the path where the plugin file will be saved
705
600
  const filePath = path.join(this.matterbridge.matterbridgeDirectory, 'uploads', filename);
706
601
  try {
707
- // Move the uploaded file to the specified path
708
602
  const fs = await import('node:fs');
709
603
  await fs.promises.rename(file.path, filePath);
710
604
  this.log.info(`File ${plg}${filename}${nf} uploaded successfully`);
711
- // Install the plugin package
712
605
  if (filename.endsWith('.tgz')) {
713
606
  const { spawnCommand } = await import('./utils/spawn.js');
714
607
  await spawnCommand(this.matterbridge, 'npm', ['install', '-g', filePath, '--omit=dev', '--verbose'], 'install', filename);
@@ -728,7 +621,6 @@ export class Frontend extends EventEmitter {
728
621
  res.status(500).send(`Error uploading or installing plugin package ${filename}`);
729
622
  }
730
623
  });
731
- // Fallback for routing (must be the last route)
732
624
  this.expressApp.use((req, res) => {
733
625
  this.log.debug(`The frontend sent ${req.url} method ${req.method}: sending index.html as fallback`);
734
626
  res.sendFile(path.join(this.matterbridge.rootDirectory, 'frontend/build/index.html'));
@@ -738,16 +630,13 @@ export class Frontend extends EventEmitter {
738
630
  async stop() {
739
631
  this.log.debug('Stopping the frontend...');
740
632
  const ws = await import('ws');
741
- // Remove listeners from the express app
742
633
  if (this.expressApp) {
743
634
  this.expressApp.removeAllListeners();
744
635
  this.expressApp = undefined;
745
636
  this.log.debug('Frontend app closed successfully');
746
637
  }
747
- // Close the WebSocket server
748
638
  if (this.webSocketServer) {
749
639
  this.log.debug('Closing WebSocket server...');
750
- // Close all active connections
751
640
  this.webSocketServer.clients.forEach((client) => {
752
641
  if (client.readyState === ws.WebSocket.OPEN) {
753
642
  client.close();
@@ -756,7 +645,6 @@ export class Frontend extends EventEmitter {
756
645
  await withTimeout(new Promise((resolve) => {
757
646
  this.webSocketServer?.close((error) => {
758
647
  if (error) {
759
- // istanbul ignore next
760
648
  this.log.error(`Error closing WebSocket server: ${error}`);
761
649
  }
762
650
  else {
@@ -769,27 +657,8 @@ export class Frontend extends EventEmitter {
769
657
  this.webSocketServer.removeAllListeners();
770
658
  this.webSocketServer = undefined;
771
659
  }
772
- // Close the http server
773
660
  if (this.httpServer) {
774
661
  this.log.debug('Closing http server...');
775
- /*
776
- await withTimeout(
777
- new Promise<void>((resolve) => {
778
- this.httpServer?.close((error) => {
779
- if (error) {
780
- // istanbul ignore next
781
- this.log.error(`Error closing http server: ${error}`);
782
- } else {
783
- this.log.debug('Http server closed successfully');
784
- this.emit('server_stopped');
785
- }
786
- resolve();
787
- });
788
- }),
789
- 5000,
790
- false,
791
- );
792
- */
793
662
  this.httpServer.close();
794
663
  this.log.debug('Http server closed successfully');
795
664
  this.listening = false;
@@ -798,27 +667,8 @@ export class Frontend extends EventEmitter {
798
667
  this.httpServer = undefined;
799
668
  this.log.debug('Frontend http server closed successfully');
800
669
  }
801
- // Close the https server
802
670
  if (this.httpsServer) {
803
671
  this.log.debug('Closing https server...');
804
- /*
805
- await withTimeout(
806
- new Promise<void>((resolve) => {
807
- this.httpsServer?.close((error) => {
808
- if (error) {
809
- // istanbul ignore next
810
- this.log.error(`Error closing https server: ${error}`);
811
- } else {
812
- this.log.debug('Https server closed successfully');
813
- this.emit('server_stopped');
814
- }
815
- resolve();
816
- });
817
- }),
818
- 5000,
819
- false,
820
- );
821
- */
822
672
  this.httpsServer.close();
823
673
  this.log.debug('Https server closed successfully');
824
674
  this.listening = false;
@@ -829,13 +679,7 @@ export class Frontend extends EventEmitter {
829
679
  }
830
680
  this.log.debug('Frontend stopped successfully');
831
681
  }
832
- /**
833
- * Retrieves the api settings data.
834
- *
835
- * @returns {Promise<{ matterbridgeInformation: MatterbridgeInformation, systemInformation: SystemInformation }>} A promise that resolve in the api settings object.
836
- */
837
682
  async getApiSettings() {
838
- // Update the variable system information properties
839
683
  this.matterbridge.systemInformation.totalMemory = formatMemoryUsage(os.totalmem());
840
684
  this.matterbridge.systemInformation.freeMemory = formatMemoryUsage(os.freemem());
841
685
  this.matterbridge.systemInformation.systemUptime = formatOsUpTime(os.uptime());
@@ -845,7 +689,6 @@ export class Frontend extends EventEmitter {
845
689
  this.matterbridge.systemInformation.rss = formatMemoryUsage(process.memoryUsage().rss);
846
690
  this.matterbridge.systemInformation.heapTotal = formatMemoryUsage(process.memoryUsage().heapTotal);
847
691
  this.matterbridge.systemInformation.heapUsed = formatMemoryUsage(process.memoryUsage().heapUsed);
848
- // Create the matterbridge information
849
692
  const info = {
850
693
  homeDirectory: this.matterbridge.homeDirectory,
851
694
  rootDirectory: this.matterbridge.rootDirectory,
@@ -881,15 +724,9 @@ export class Frontend extends EventEmitter {
881
724
  };
882
725
  return { systemInformation: this.matterbridge.systemInformation, matterbridgeInformation: info };
883
726
  }
884
- /**
885
- * Retrieves the reachable attribute.
886
- *
887
- * @param {MatterbridgeEndpoint} device - The MatterbridgeEndpoint object.
888
- * @returns {boolean} The reachable attribute.
889
- */
890
727
  getReachability(device) {
891
728
  if (this.matterbridge.hasCleanupStarted)
892
- return false; // Skip if cleanup has started
729
+ return false;
893
730
  if (!device.lifecycle.isReady || device.construction.status !== Lifecycle.Status.Active)
894
731
  return false;
895
732
  if (device.hasClusterServer(BridgedDeviceBasicInformation.Cluster.id))
@@ -900,15 +737,9 @@ export class Frontend extends EventEmitter {
900
737
  return true;
901
738
  return false;
902
739
  }
903
- /**
904
- * Retrieves the power source attribute.
905
- *
906
- * @param {MatterbridgeEndpoint} endpoint - The MatterbridgeDevice to retrieve the power source from.
907
- * @returns {'ac' | 'dc' | 'ok' | 'warning' | 'critical' | undefined} The power source attribute.
908
- */
909
740
  getPowerSource(endpoint) {
910
741
  if (this.matterbridge.hasCleanupStarted)
911
- return; // Skip if cleanup has started
742
+ return;
912
743
  if (!endpoint.lifecycle.isReady || endpoint.construction.status !== Lifecycle.Status.Active)
913
744
  return undefined;
914
745
  const powerSource = (device) => {
@@ -923,25 +754,16 @@ export class Frontend extends EventEmitter {
923
754
  }
924
755
  return;
925
756
  };
926
- // Root endpoint
927
757
  if (endpoint.hasClusterServer(PowerSource.Cluster.id))
928
758
  return powerSource(endpoint);
929
- // Child endpoints
930
759
  for (const child of endpoint.getChildEndpoints()) {
931
760
  if (child.hasClusterServer(PowerSource.Cluster.id))
932
761
  return powerSource(child);
933
762
  }
934
763
  }
935
- /**
936
- * Retrieves the cluster text description from a given device.
937
- * The output is a string with the attributes description of the cluster servers in the device to show in the frontend.
938
- *
939
- * @param {MatterbridgeEndpoint} device - The MatterbridgeEndpoint to retrieve the cluster text from.
940
- * @returns {string} The attributes description of the cluster servers in the device.
941
- */
942
764
  getClusterTextFromDevice(device) {
943
765
  if (this.matterbridge.hasCleanupStarted)
944
- return ''; // Skip if cleanup has started
766
+ return '';
945
767
  if (!device.lifecycle.isReady || device.construction.status !== Lifecycle.Status.Active)
946
768
  return '';
947
769
  const getUserLabel = (device) => {
@@ -951,7 +773,6 @@ export class Frontend extends EventEmitter {
951
773
  if (composed)
952
774
  return 'Composed: ' + composed.value;
953
775
  }
954
- // istanbul ignore next cause is not reachable
955
776
  return '';
956
777
  };
957
778
  const getFixedLabel = (device) => {
@@ -961,13 +782,11 @@ export class Frontend extends EventEmitter {
961
782
  if (composed)
962
783
  return 'Composed: ' + composed.value;
963
784
  }
964
- // istanbul ignore next cause is not reacheable
965
785
  return '';
966
786
  };
967
787
  let attributes = '';
968
788
  let supportedModes = [];
969
789
  device.forEachAttribute((clusterName, clusterId, attributeName, attributeId, attributeValue) => {
970
- // console.log(`${device.deviceName} => Cluster: ${clusterName}-${clusterId} Attribute: ${attributeName}-${attributeId} Value(${typeof attributeValue}): ${attributeValue}`);
971
790
  if (typeof attributeValue === 'undefined' || attributeValue === undefined)
972
791
  return;
973
792
  if (clusterName === 'onOff' && attributeName === 'onOff')
@@ -1057,17 +876,11 @@ export class Frontend extends EventEmitter {
1057
876
  if (clusterName === 'userLabel' && attributeName === 'labelList')
1058
877
  attributes += `${getUserLabel(device)} `;
1059
878
  });
1060
- // console.log(`${device.deviceName}.forEachAttribute: ${attributes}`);
1061
879
  return attributes.trimStart().trimEnd();
1062
880
  }
1063
- /**
1064
- * Retrieves the registered plugins sanitized for res.json().
1065
- *
1066
- * @returns {ApiPlugin[]} An array of BaseRegisteredPlugin.
1067
- */
1068
881
  getPlugins() {
1069
882
  if (this.matterbridge.hasCleanupStarted)
1070
- return []; // Skip if cleanup has started
883
+ return [];
1071
884
  const plugins = [];
1072
885
  for (const plugin of this.matterbridge.plugins.array()) {
1073
886
  plugins.push({
@@ -1095,27 +908,18 @@ export class Frontend extends EventEmitter {
1095
908
  schemaJson: plugin.schemaJson,
1096
909
  hasWhiteList: plugin.configJson?.whiteList !== undefined,
1097
910
  hasBlackList: plugin.configJson?.blackList !== undefined,
1098
- // Childbridge mode specific data
1099
911
  matter: plugin.serverNode ? this.matterbridge.getServerNodeData(plugin.serverNode) : undefined,
1100
912
  });
1101
913
  }
1102
914
  return plugins;
1103
915
  }
1104
- /**
1105
- * Retrieves the devices from Matterbridge.
1106
- *
1107
- * @param {string} [pluginName] - The name of the plugin to filter devices by.
1108
- * @returns {ApiDevice[]} An array of ApiDevices for the frontend.
1109
- */
1110
916
  getDevices(pluginName) {
1111
917
  if (this.matterbridge.hasCleanupStarted)
1112
- return []; // Skip if cleanup has started
918
+ return [];
1113
919
  const devices = [];
1114
920
  for (const device of this.matterbridge.devices.array()) {
1115
- // Filter by pluginName if provided
1116
921
  if (pluginName && pluginName !== device.plugin)
1117
922
  continue;
1118
- // Check if the device has the required properties
1119
923
  if (!device.plugin || !device.deviceType || !device.name || !device.deviceName || !device.serialNumber || !device.uniqueId || !device.lifecycle.isReady)
1120
924
  continue;
1121
925
  devices.push({
@@ -1135,39 +939,24 @@ export class Frontend extends EventEmitter {
1135
939
  }
1136
940
  return devices;
1137
941
  }
1138
- /**
1139
- * Retrieves the clusters from a given plugin and endpoint number.
1140
- *
1141
- * Response for /api/clusters
1142
- *
1143
- * @param {string} pluginName - The name of the plugin.
1144
- * @param {number} endpointNumber - The endpoint number.
1145
- * @returns {ApiClusters | undefined} A promise that resolves to the clusters or undefined if not found.
1146
- */
1147
942
  getClusters(pluginName, endpointNumber) {
1148
943
  if (this.matterbridge.hasCleanupStarted)
1149
- return; // Skip if cleanup has started
944
+ return;
1150
945
  const endpoint = this.matterbridge.devices.array().find((d) => d.plugin === pluginName && d.maybeNumber === endpointNumber);
1151
946
  if (!endpoint || !endpoint.plugin || !endpoint.maybeNumber || !endpoint.maybeId || !endpoint.deviceName || !endpoint.serialNumber) {
1152
947
  this.log.error(`getClusters: no device found for plugin ${pluginName} and endpoint number ${endpointNumber}`);
1153
948
  return;
1154
949
  }
1155
- // this.log.debug(`***getClusters: getting clusters for device ${endpoint.deviceName} plugin ${pluginName} endpoint number ${endpointNumber}`);
1156
- // Get the device types from the main endpoint
1157
950
  const deviceTypes = [];
1158
951
  const clusters = [];
1159
952
  endpoint.state.descriptor.deviceTypeList.forEach((d) => {
1160
953
  deviceTypes.push(d.deviceType);
1161
954
  });
1162
- // Get the clusters from the main endpoint
1163
955
  endpoint.forEachAttribute((clusterName, clusterId, attributeName, attributeId, attributeValue) => {
1164
956
  if (typeof attributeValue === 'undefined' || attributeValue === undefined)
1165
957
  return;
1166
958
  if (clusterName === 'EveHistory' && ['configDataGet', 'configDataSet', 'historyStatus', 'historyEntries', 'historyRequest', 'historySetTime', 'rLoc'].includes(attributeName))
1167
959
  return;
1168
- // console.log(
1169
- // `${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}`,
1170
- // );
1171
960
  clusters.push({
1172
961
  endpoint: endpoint.number.toString(),
1173
962
  number: endpoint.number,
@@ -1181,19 +970,12 @@ export class Frontend extends EventEmitter {
1181
970
  attributeLocalValue: attributeValue,
1182
971
  });
1183
972
  });
1184
- // Get the child endpoints
1185
973
  const childEndpoints = endpoint.getChildEndpoints();
1186
- // if (childEndpoints.length === 0) {
1187
- // this.log.debug(`***getClusters: found ${childEndpoints.length} child endpoints for device ${endpoint.deviceName} plugin ${pluginName} and endpoint number ${endpointNumber}`);
1188
- // }
1189
974
  childEndpoints.forEach((childEndpoint) => {
1190
- // istanbul ignore if cause is not reachable: should never happen but ...
1191
975
  if (!childEndpoint.maybeId || !childEndpoint.maybeNumber) {
1192
976
  this.log.error(`getClusters: no child endpoint found for plugin ${pluginName} and endpoint number ${endpointNumber}`);
1193
977
  return;
1194
978
  }
1195
- // this.log.debug(`***getClusters: getting clusters for child endpoint ${childEndpoint.id} of device ${endpoint.deviceName} plugin ${pluginName} endpoint number ${childEndpoint.number}`);
1196
- // Get the device types of the child endpoint
1197
979
  const deviceTypes = [];
1198
980
  childEndpoint.state.descriptor.deviceTypeList.forEach((d) => {
1199
981
  deviceTypes.push(d.deviceType);
@@ -1203,9 +985,6 @@ export class Frontend extends EventEmitter {
1203
985
  return;
1204
986
  if (clusterName === 'EveHistory' && ['configDataGet', 'configDataSet', 'historyStatus', 'historyEntries', 'historyRequest', 'historySetTime', 'rLoc'].includes(attributeName))
1205
987
  return;
1206
- // console.log(
1207
- // `${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}`,
1208
- // );
1209
988
  clusters.push({
1210
989
  endpoint: childEndpoint.number.toString(),
1211
990
  number: childEndpoint.number,
@@ -1222,13 +1001,6 @@ export class Frontend extends EventEmitter {
1222
1001
  });
1223
1002
  return { plugin: endpoint.plugin, deviceName: endpoint.deviceName, serialNumber: endpoint.serialNumber, number: endpoint.number, id: endpoint.id, deviceTypes, clusters };
1224
1003
  }
1225
- /**
1226
- * Handles incoming websocket api request messages from the Matterbridge frontend.
1227
- *
1228
- * @param {WebSocket} client - The websocket client that sent the message.
1229
- * @param {WebSocket.RawData} message - The raw data of the message received from the client.
1230
- * @returns {Promise<void>} A promise that resolves when the message has been handled.
1231
- */
1232
1004
  async wsMessageHandler(client, message) {
1233
1005
  let data;
1234
1006
  const sendResponse = (data) => {
@@ -1248,7 +1020,7 @@ export class Frontend extends EventEmitter {
1248
1020
  };
1249
1021
  try {
1250
1022
  data = JSON.parse(message.toString());
1251
- if (!isValidNumber(data.id) || !isValidString(data.dst) || !isValidString(data.src) || !isValidString(data.method) /* || !isValidObject(data.params)*/ || data.dst !== 'Matterbridge') {
1023
+ if (!isValidNumber(data.id) || !isValidString(data.dst) || !isValidString(data.src) || !isValidString(data.method) || data.dst !== 'Matterbridge') {
1252
1024
  this.log.error(`Invalid message from websocket client: ${debugStringify(data)}`);
1253
1025
  sendResponse({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, error: 'Invalid message' });
1254
1026
  return;
@@ -1322,7 +1094,6 @@ export class Frontend extends EventEmitter {
1322
1094
  return;
1323
1095
  })
1324
1096
  .catch((_error) => {
1325
- //
1326
1097
  });
1327
1098
  }
1328
1099
  else {
@@ -1370,7 +1141,6 @@ export class Frontend extends EventEmitter {
1370
1141
  return;
1371
1142
  })
1372
1143
  .catch((_error) => {
1373
- //
1374
1144
  });
1375
1145
  }
1376
1146
  sendResponse({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, success: true });
@@ -1396,7 +1166,6 @@ export class Frontend extends EventEmitter {
1396
1166
  const plugin = this.matterbridge.plugins.get(data.params.pluginName);
1397
1167
  await this.matterbridge.plugins.shutdown(plugin, 'The plugin is restarting.', false, true);
1398
1168
  if (plugin.serverNode) {
1399
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1400
1169
  await this.matterbridge.stopServerNode(plugin.serverNode);
1401
1170
  plugin.serverNode = undefined;
1402
1171
  }
@@ -1406,20 +1175,18 @@ export class Frontend extends EventEmitter {
1406
1175
  this.matterbridge.devices.remove(device);
1407
1176
  }
1408
1177
  }
1409
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1410
1178
  if (plugin.type === 'DynamicPlatform' && !plugin.locked)
1411
1179
  await this.matterbridge.createDynamicPlugin(plugin);
1412
1180
  await this.matterbridge.plugins.load(plugin, true, 'The plugin has been restarted', true);
1413
- plugin.restartRequired = false; // Reset plugin restartRequired
1181
+ plugin.restartRequired = false;
1414
1182
  let needRestart = 0;
1415
1183
  for (const plugin of this.matterbridge.plugins) {
1416
1184
  if (plugin.restartRequired)
1417
1185
  needRestart++;
1418
1186
  }
1419
1187
  if (needRestart === 0) {
1420
- this.wssSendRestartNotRequired(true); // Reset global restart required message
1188
+ this.wssSendRestartNotRequired(true);
1421
1189
  }
1422
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1423
1190
  if (plugin.serverNode)
1424
1191
  await this.matterbridge.startServerNode(plugin.serverNode);
1425
1192
  this.wssSendSnackbarMessage(`Restarted plugin ${data.params.pluginName}`, 5, 'success');
@@ -1680,22 +1447,22 @@ export class Frontend extends EventEmitter {
1680
1447
  if (isValidString(data.params.value, 4)) {
1681
1448
  this.log.debug('Matterbridge logger level:', data.params.value);
1682
1449
  if (data.params.value === 'Debug') {
1683
- await this.matterbridge.setLogLevel("debug" /* LogLevel.DEBUG */);
1450
+ await this.matterbridge.setLogLevel("debug");
1684
1451
  }
1685
1452
  else if (data.params.value === 'Info') {
1686
- await this.matterbridge.setLogLevel("info" /* LogLevel.INFO */);
1453
+ await this.matterbridge.setLogLevel("info");
1687
1454
  }
1688
1455
  else if (data.params.value === 'Notice') {
1689
- await this.matterbridge.setLogLevel("notice" /* LogLevel.NOTICE */);
1456
+ await this.matterbridge.setLogLevel("notice");
1690
1457
  }
1691
1458
  else if (data.params.value === 'Warn') {
1692
- await this.matterbridge.setLogLevel("warn" /* LogLevel.WARN */);
1459
+ await this.matterbridge.setLogLevel("warn");
1693
1460
  }
1694
1461
  else if (data.params.value === 'Error') {
1695
- await this.matterbridge.setLogLevel("error" /* LogLevel.ERROR */);
1462
+ await this.matterbridge.setLogLevel("error");
1696
1463
  }
1697
1464
  else if (data.params.value === 'Fatal') {
1698
- await this.matterbridge.setLogLevel("fatal" /* LogLevel.FATAL */);
1465
+ await this.matterbridge.setLogLevel("fatal");
1699
1466
  }
1700
1467
  await this.matterbridge.nodeContext?.set('matterbridgeLogLevel', this.log.logLevel);
1701
1468
  sendResponse({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, success: true });
@@ -1706,7 +1473,6 @@ export class Frontend extends EventEmitter {
1706
1473
  this.log.debug('Matterbridge file log:', data.params.value);
1707
1474
  this.matterbridge.fileLogger = data.params.value;
1708
1475
  await this.matterbridge.nodeContext?.set('matterbridgeFileLog', data.params.value);
1709
- // Create the file logger for matterbridge
1710
1476
  if (data.params.value)
1711
1477
  AnsiLogger.setGlobalLogfile(path.join(this.matterbridge.matterbridgeDirectory, MATTERBRIDGE_LOGGER_FILE), await this.matterbridge.getLogLevel(), true);
1712
1478
  else
@@ -1784,7 +1550,6 @@ export class Frontend extends EventEmitter {
1784
1550
  }
1785
1551
  break;
1786
1552
  case 'setmatterport':
1787
- // eslint-disable-next-line no-case-declarations
1788
1553
  const port = isValidString(data.params.value) ? parseInt(data.params.value) : 0;
1789
1554
  if (isValidNumber(port, 5540, 5600)) {
1790
1555
  this.log.debug(`Set matter commissioning port to ${CYAN}${port}${db}`);
@@ -1804,7 +1569,6 @@ export class Frontend extends EventEmitter {
1804
1569
  }
1805
1570
  break;
1806
1571
  case 'setmatterdiscriminator':
1807
- // eslint-disable-next-line no-case-declarations
1808
1572
  const discriminator = isValidString(data.params.value) ? parseInt(data.params.value) : 0;
1809
1573
  if (isValidNumber(discriminator, 0, 4095)) {
1810
1574
  this.log.debug(`Set matter commissioning discriminator to ${CYAN}${discriminator}${db}`);
@@ -1824,7 +1588,6 @@ export class Frontend extends EventEmitter {
1824
1588
  }
1825
1589
  break;
1826
1590
  case 'setmatterpasscode':
1827
- // eslint-disable-next-line no-case-declarations
1828
1591
  const passcode = isValidString(data.params.value) ? parseInt(data.params.value) : 0;
1829
1592
  if (isValidNumber(passcode, 1, 99999998) && CommissioningOptions.FORBIDDEN_PASSCODES.includes(passcode) === false) {
1830
1593
  this.matterbridge.passcode = passcode;
@@ -1870,19 +1633,15 @@ export class Frontend extends EventEmitter {
1870
1633
  return;
1871
1634
  }
1872
1635
  const config = plugin.configJson;
1873
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1874
1636
  const select = plugin.schemaJson?.properties?.blackList?.selectFrom;
1875
- // this.log.debug(`SelectDevice(selectMode ${select}) data ${debugStringify(data)}`);
1876
1637
  if (select === 'serial')
1877
1638
  this.log.info(`Selected device serial ${data.params.serial}`);
1878
1639
  if (select === 'name')
1879
1640
  this.log.info(`Selected device name ${data.params.name}`);
1880
1641
  if (config && select && (select === 'serial' || select === 'name')) {
1881
- // Remove postfix from the serial if it exists
1882
1642
  if (config.postfix) {
1883
1643
  data.params.serial = data.params.serial.replace('-' + config.postfix, '');
1884
1644
  }
1885
- // Add the serial to the whiteList if the whiteList exists and the serial or name is not already in it
1886
1645
  if (isValidArray(config.whiteList, 1)) {
1887
1646
  if (select === 'serial' && !config.whiteList.includes(data.params.serial)) {
1888
1647
  config.whiteList.push(data.params.serial);
@@ -1891,7 +1650,6 @@ export class Frontend extends EventEmitter {
1891
1650
  config.whiteList.push(data.params.name);
1892
1651
  }
1893
1652
  }
1894
- // Remove the serial from the blackList if the blackList exists and the serial or name is in it
1895
1653
  if (isValidArray(config.blackList, 1)) {
1896
1654
  if (select === 'serial' && config.blackList.includes(data.params.serial)) {
1897
1655
  config.blackList = config.blackList.filter((item) => item !== localData.params.serial);
@@ -1919,9 +1677,7 @@ export class Frontend extends EventEmitter {
1919
1677
  return;
1920
1678
  }
1921
1679
  const config = plugin.configJson;
1922
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1923
1680
  const select = plugin.schemaJson?.properties?.blackList?.selectFrom;
1924
- // this.log.debug(`UnselectDevice(selectMode ${select}) data ${debugStringify(data)}`);
1925
1681
  if (select === 'serial')
1926
1682
  this.log.info(`Unselected device serial ${data.params.serial}`);
1927
1683
  if (select === 'name')
@@ -1930,7 +1686,6 @@ export class Frontend extends EventEmitter {
1930
1686
  if (config.postfix) {
1931
1687
  data.params.serial = data.params.serial.replace('-' + config.postfix, '');
1932
1688
  }
1933
- // Remove the serial from the whiteList if the whiteList exists and the serial is in it
1934
1689
  if (isValidArray(config.whiteList, 1)) {
1935
1690
  if (select === 'serial' && config.whiteList.includes(data.params.serial)) {
1936
1691
  config.whiteList = config.whiteList.filter((item) => item !== localData.params.serial);
@@ -1939,7 +1694,6 @@ export class Frontend extends EventEmitter {
1939
1694
  config.whiteList = config.whiteList.filter((item) => item !== localData.params.name);
1940
1695
  }
1941
1696
  }
1942
- // Add the serial to the blackList
1943
1697
  if (isValidArray(config.blackList)) {
1944
1698
  if (select === 'serial' && !config.blackList.includes(data.params.serial)) {
1945
1699
  config.blackList.push(data.params.serial);
@@ -1962,7 +1716,6 @@ export class Frontend extends EventEmitter {
1962
1716
  }
1963
1717
  }
1964
1718
  else {
1965
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1966
1719
  const localData = data;
1967
1720
  this.log.error(`Invalid method from websocket client: ${debugStringify(localData)}`);
1968
1721
  sendResponse({ id: localData.id, method: localData.method, src: 'Matterbridge', dst: localData.src, error: 'Invalid method' });
@@ -1972,46 +1725,23 @@ export class Frontend extends EventEmitter {
1972
1725
  inspectError(this.log, `Error processing message "${message}" from websocket client`, error);
1973
1726
  }
1974
1727
  }
1975
- /**
1976
- * Sends a WebSocket log message to all connected clients. The function is called by AnsiLogger.setGlobalCallback.
1977
- *
1978
- * @param {string} level - The logger level of the message: debug info notice warn error fatal...
1979
- * @param {string} time - The time string of the message
1980
- * @param {string} name - The logger name of the message
1981
- * @param {string} message - The content of the message.
1982
- *
1983
- * @remarks
1984
- * The function removes ANSI escape codes, leading asterisks, non-printable characters, and replaces all occurrences of \t and \n.
1985
- * It also replaces all occurrences of \" with " and angle-brackets with &lt; and &gt;.
1986
- * The function sends the message to all connected clients.
1987
- */
1988
1728
  wssSendLogMessage(level, time, name, message) {
1989
1729
  if (!this.listening || this.webSocketServer?.clients.size === 0)
1990
1730
  return;
1991
1731
  if (!level || !time || !name || !message)
1992
1732
  return;
1993
- // Remove ANSI escape codes from the message
1994
- // eslint-disable-next-line no-control-regex
1995
1733
  message = message.replace(/\x1B\[[0-9;]*[m|s|u|K]/g, '');
1996
- // Remove leading asterisks from the message
1997
1734
  message = message.replace(/^\*+/, '');
1998
- // Replace all occurrences of \t and \n
1999
1735
  message = message.replace(/[\t\n]/g, '');
2000
- // Remove non-printable characters
2001
- // eslint-disable-next-line no-control-regex
2002
1736
  message = message.replace(/[\x00-\x1F\x7F]/g, '');
2003
- // Replace all occurrences of \" with "
2004
1737
  message = message.replace(/\\"/g, '"');
2005
- // Define the maximum allowed length for continuous characters without a space
2006
1738
  const maxContinuousLength = 100;
2007
1739
  const keepStartLength = 20;
2008
1740
  const keepEndLength = 20;
2009
- // Split the message into words
2010
1741
  if (level !== 'spawn') {
2011
1742
  message = message
2012
1743
  .split(' ')
2013
1744
  .map((word) => {
2014
- // If the word length exceeds the max continuous length, insert spaces and truncate
2015
1745
  if (word.length > maxContinuousLength) {
2016
1746
  return word.slice(0, keepStartLength) + ' ... ' + word.slice(-keepEndLength);
2017
1747
  }
@@ -2019,34 +1749,14 @@ export class Frontend extends EventEmitter {
2019
1749
  })
2020
1750
  .join(' ');
2021
1751
  }
2022
- // Send the message to all connected clients
2023
1752
  this.wssBroadcastMessage({ id: 0, src: 'Matterbridge', dst: 'Frontend', method: 'log', success: true, response: { level, time, name, message } });
2024
1753
  }
2025
- /**
2026
- * Sends a need to refresh WebSocket message to all connected clients.
2027
- *
2028
- * @param {string} changed - The changed value.
2029
- * @param {Record<string, unknown>} params - Additional parameters to send with the message.
2030
- * possible values for changed:
2031
- * - 'settings' (when the bridge has started in bridge mode or childbridge mode and when update finds a new version)
2032
- * - 'plugins'
2033
- * - 'devices'
2034
- * - 'matter' with param 'matter' (QRDiv component)
2035
- * @param {ApiMatter} params.matter - The matter device that has changed. Required if changed is 'matter'.
2036
- */
2037
1754
  wssSendRefreshRequired(changed, params) {
2038
1755
  if (!this.listening || this.webSocketServer?.clients.size === 0)
2039
1756
  return;
2040
1757
  this.log.debug('Sending a refresh required message to all connected clients');
2041
- // Send the message to all connected clients
2042
1758
  this.wssBroadcastMessage({ id: 0, src: 'Matterbridge', dst: 'Frontend', method: 'refresh_required', success: true, response: { changed, ...params } });
2043
1759
  }
2044
- /**
2045
- * Sends a need to restart WebSocket message to all connected clients.
2046
- *
2047
- * @param {boolean} snackbar - If true, a snackbar message will be sent to all connected clients. Default is true.
2048
- * @param {boolean} fixed - If true, the restart is fixed and will not be reset by plugin restarts. Default is false.
2049
- */
2050
1760
  wssSendRestartRequired(snackbar = true, fixed = false) {
2051
1761
  if (!this.listening || this.webSocketServer?.clients.size === 0)
2052
1762
  return;
@@ -2055,14 +1765,8 @@ export class Frontend extends EventEmitter {
2055
1765
  this.matterbridge.fixedRestartRequired = fixed;
2056
1766
  if (snackbar === true)
2057
1767
  this.wssSendSnackbarMessage(`Restart required`, 0);
2058
- // Send the message to all connected clients
2059
1768
  this.wssBroadcastMessage({ id: 0, src: 'Matterbridge', dst: 'Frontend', method: 'restart_required', success: true, response: { fixed } });
2060
1769
  }
2061
- /**
2062
- * Sends a no need to restart WebSocket message to all connected clients.
2063
- *
2064
- * @param {boolean} snackbar - If true, the snackbar message will be cleared from all connected clients. Default is true.
2065
- */
2066
1770
  wssSendRestartNotRequired(snackbar = true) {
2067
1771
  if (!this.listening || this.webSocketServer?.clients.size === 0)
2068
1772
  return;
@@ -2070,133 +1774,57 @@ export class Frontend extends EventEmitter {
2070
1774
  this.matterbridge.restartRequired = false;
2071
1775
  if (snackbar === true)
2072
1776
  this.wssSendCloseSnackbarMessage(`Restart required`);
2073
- // Send the message to all connected clients
2074
1777
  this.wssBroadcastMessage({ id: 0, src: 'Matterbridge', dst: 'Frontend', method: 'restart_not_required', success: true });
2075
1778
  }
2076
- /**
2077
- * Sends a need to update WebSocket message to all connected clients.
2078
- *
2079
- * @param {boolean} devVersion - If true, the update is for a development version. Default is false.
2080
- */
2081
1779
  wssSendUpdateRequired(devVersion = false) {
2082
1780
  if (!this.listening || this.webSocketServer?.clients.size === 0)
2083
1781
  return;
2084
1782
  this.log.debug('Sending an update required message to all connected clients');
2085
1783
  this.matterbridge.updateRequired = true;
2086
- // Send the message to all connected clients
2087
1784
  this.wssBroadcastMessage({ id: 0, src: 'Matterbridge', dst: 'Frontend', method: 'update_required', success: true, response: { devVersion } });
2088
1785
  }
2089
- /**
2090
- * Sends a cpu update message to all connected clients.
2091
- *
2092
- * @param {number} cpuUsage - The CPU usage percentage to send.
2093
- * @param {number} processCpuUsage - The CPU usage percentage of the process to send.
2094
- */
2095
1786
  wssSendCpuUpdate(cpuUsage, processCpuUsage) {
2096
1787
  if (!this.listening || this.webSocketServer?.clients.size === 0)
2097
1788
  return;
2098
1789
  if (hasParameter('debug'))
2099
1790
  this.log.debug('Sending a cpu update message to all connected clients');
2100
- // Send the message to all connected clients
2101
1791
  this.wssBroadcastMessage({ id: 0, src: 'Matterbridge', dst: 'Frontend', method: 'cpu_update', success: true, response: { cpuUsage: Math.round(cpuUsage * 100) / 100, processCpuUsage: Math.round(processCpuUsage * 100) / 100 } });
2102
1792
  }
2103
- /**
2104
- * Sends a memory update message to all connected clients.
2105
- *
2106
- * @param {string} totalMemory - The total memory in bytes.
2107
- * @param {string} freeMemory - The free memory in bytes.
2108
- * @param {string} rss - The resident set size in bytes.
2109
- * @param {string} heapTotal - The total heap memory in bytes.
2110
- * @param {string} heapUsed - The used heap memory in bytes.
2111
- * @param {string} external - The external memory in bytes.
2112
- * @param {string} arrayBuffers - The array buffers memory in bytes.
2113
- */
2114
1793
  wssSendMemoryUpdate(totalMemory, freeMemory, rss, heapTotal, heapUsed, external, arrayBuffers) {
2115
1794
  if (!this.listening || this.webSocketServer?.clients.size === 0)
2116
1795
  return;
2117
1796
  if (hasParameter('debug'))
2118
1797
  this.log.debug('Sending a memory update message to all connected clients');
2119
- // Send the message to all connected clients
2120
1798
  this.wssBroadcastMessage({ id: 0, src: 'Matterbridge', dst: 'Frontend', method: 'memory_update', success: true, response: { totalMemory, freeMemory, rss, heapTotal, heapUsed, external, arrayBuffers } });
2121
1799
  }
2122
- /**
2123
- * Sends an uptime update message to all connected clients.
2124
- *
2125
- * @param {string} systemUptime - The system uptime in a human-readable format.
2126
- * @param {string} processUptime - The process uptime in a human-readable format.
2127
- */
2128
1800
  wssSendUptimeUpdate(systemUptime, processUptime) {
2129
1801
  if (!this.listening || this.webSocketServer?.clients.size === 0)
2130
1802
  return;
2131
1803
  if (hasParameter('debug'))
2132
1804
  this.log.debug('Sending a uptime update message to all connected clients');
2133
- // Send the message to all connected clients
2134
1805
  this.wssBroadcastMessage({ id: 0, src: 'Matterbridge', dst: 'Frontend', method: 'uptime_update', success: true, response: { systemUptime, processUptime } });
2135
1806
  }
2136
- /**
2137
- * Sends an open snackbar message to all connected clients.
2138
- *
2139
- * @param {string} message - The message to send.
2140
- * @param {number} timeout - The timeout in seconds for the snackbar message. Default is 5 seconds.
2141
- * @param {'info' | 'warning' | 'error' | 'success'} severity - The severity of the message.
2142
- * possible values are: 'info', 'warning', 'error', 'success'. Default is 'info'.
2143
- *
2144
- * @remarks
2145
- * If timeout is 0, the snackbar message will be displayed until closed by the user.
2146
- */
2147
1807
  wssSendSnackbarMessage(message, timeout = 5, severity = 'info') {
2148
1808
  if (!this.listening || this.webSocketServer?.clients.size === 0)
2149
1809
  return;
2150
1810
  this.log.debug('Sending a snackbar message to all connected clients');
2151
- // Send the message to all connected clients
2152
1811
  this.wssBroadcastMessage({ id: 0, src: 'Matterbridge', dst: 'Frontend', method: 'snackbar', success: true, response: { message, timeout, severity } });
2153
1812
  }
2154
- /**
2155
- * Sends a close snackbar message to all connected clients.
2156
- * It will close the snackbar message with the same message and timeout = 0.
2157
- *
2158
- * @param {string} message - The message to send.
2159
- */
2160
1813
  wssSendCloseSnackbarMessage(message) {
2161
1814
  if (!this.listening || this.webSocketServer?.clients.size === 0)
2162
1815
  return;
2163
1816
  this.log.debug('Sending a close snackbar message to all connected clients');
2164
- // Send the message to all connected clients
2165
1817
  this.wssBroadcastMessage({ id: 0, src: 'Matterbridge', dst: 'Frontend', method: 'close_snackbar', success: true, response: { message } });
2166
1818
  }
2167
- /**
2168
- * Sends an attribute update message to all connected WebSocket clients.
2169
- *
2170
- * @param {string | undefined} plugin - The name of the plugin.
2171
- * @param {string | undefined} serialNumber - The serial number of the device.
2172
- * @param {string | undefined} uniqueId - The unique identifier of the device.
2173
- * @param {EndpointNumber} number - The endpoint number where the attribute belongs.
2174
- * @param {string} id - The endpoint id where the attribute belongs.
2175
- * @param {string} cluster - The cluster name where the attribute belongs.
2176
- * @param {string} attribute - The name of the attribute that changed.
2177
- * @param {number | string | boolean} value - The new value of the attribute.
2178
- *
2179
- * @remarks
2180
- * This method logs a debug message and sends a JSON-formatted message to all connected WebSocket clients
2181
- * with the updated attribute information.
2182
- */
2183
1819
  wssSendAttributeChangedMessage(plugin, serialNumber, uniqueId, number, id, cluster, attribute, value) {
2184
1820
  if (!this.listening || this.webSocketServer?.clients.size === 0)
2185
1821
  return;
2186
1822
  this.log.debug('Sending an attribute update message to all connected clients');
2187
- // Send the message to all connected clients
2188
1823
  this.wssBroadcastMessage({ id: 0, src: 'Matterbridge', dst: 'Frontend', method: 'state_update', success: true, response: { plugin, serialNumber, uniqueId, number, id, cluster, attribute, value } });
2189
1824
  }
2190
- /**
2191
- * Sends a message to all connected clients.
2192
- * This is an helper function to send a broadcast message to all connected clients.
2193
- *
2194
- * @param {WsMessageBroadcast} msg - The message to send.
2195
- */
2196
1825
  wssBroadcastMessage(msg) {
2197
1826
  if (!this.listening || this.webSocketServer?.clients.size === 0)
2198
1827
  return;
2199
- // Send the message to all connected clients
2200
1828
  const stringifiedMsg = JSON.stringify(msg);
2201
1829
  if (msg.method !== 'log')
2202
1830
  this.log.debug(`Sending a broadcast message: ${debugStringify(msg)}`);
@@ -2207,4 +1835,3 @@ export class Frontend extends EventEmitter {
2207
1835
  });
2208
1836
  }
2209
1837
  }
2210
- //# sourceMappingURL=frontend.js.map