matterbridge 3.3.4 → 3.3.5-dev-20251025-26d5c31

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 (303) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/dist/broadcastServer.js +1 -92
  3. package/dist/broadcastServerTypes.js +0 -24
  4. package/dist/cli.js +1 -97
  5. package/dist/cliEmitter.js +0 -37
  6. package/dist/cliHistory.js +0 -38
  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 -24
  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 +34 -436
  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 +50 -828
  47. package/dist/matterbridgeAccessoryPlatform.js +0 -37
  48. package/dist/matterbridgeBehaviors.js +5 -68
  49. package/dist/matterbridgeDeviceTypes.js +17 -638
  50. package/dist/matterbridgeDynamicPlatform.js +0 -37
  51. package/dist/matterbridgeEndpoint.js +52 -1402
  52. package/dist/matterbridgeEndpointHelpers.js +19 -464
  53. package/dist/matterbridgePlatform.js +1 -341
  54. package/dist/matterbridgeTypes.js +0 -26
  55. package/dist/pluginManager.js +3 -319
  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 -60
  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/format.js +0 -49
  69. package/dist/utils/hex.js +0 -124
  70. package/dist/utils/inspector.js +1 -69
  71. package/dist/utils/isvalid.js +0 -101
  72. package/dist/utils/jestHelpers.js +3 -153
  73. package/dist/utils/network.js +5 -96
  74. package/dist/utils/spawn.js +0 -71
  75. package/dist/utils/tracker.js +1 -64
  76. package/dist/utils/wait.js +8 -60
  77. package/npm-shrinkwrap.json +2 -2
  78. package/package.json +1 -2
  79. package/dist/broadcastServer.d.ts +0 -112
  80. package/dist/broadcastServer.d.ts.map +0 -1
  81. package/dist/broadcastServer.js.map +0 -1
  82. package/dist/broadcastServerTypes.d.ts +0 -793
  83. package/dist/broadcastServerTypes.d.ts.map +0 -1
  84. package/dist/broadcastServerTypes.js.map +0 -1
  85. package/dist/cli.d.ts +0 -30
  86. package/dist/cli.d.ts.map +0 -1
  87. package/dist/cli.js.map +0 -1
  88. package/dist/cliEmitter.d.ts +0 -50
  89. package/dist/cliEmitter.d.ts.map +0 -1
  90. package/dist/cliEmitter.js.map +0 -1
  91. package/dist/cliHistory.d.ts +0 -48
  92. package/dist/cliHistory.d.ts.map +0 -1
  93. package/dist/cliHistory.js.map +0 -1
  94. package/dist/clusters/export.d.ts +0 -2
  95. package/dist/clusters/export.d.ts.map +0 -1
  96. package/dist/clusters/export.js.map +0 -1
  97. package/dist/defaultConfigSchema.d.ts +0 -28
  98. package/dist/defaultConfigSchema.d.ts.map +0 -1
  99. package/dist/defaultConfigSchema.js.map +0 -1
  100. package/dist/deviceManager.d.ts +0 -117
  101. package/dist/deviceManager.d.ts.map +0 -1
  102. package/dist/deviceManager.js.map +0 -1
  103. package/dist/devices/airConditioner.d.ts +0 -98
  104. package/dist/devices/airConditioner.d.ts.map +0 -1
  105. package/dist/devices/airConditioner.js.map +0 -1
  106. package/dist/devices/batteryStorage.d.ts +0 -48
  107. package/dist/devices/batteryStorage.d.ts.map +0 -1
  108. package/dist/devices/batteryStorage.js.map +0 -1
  109. package/dist/devices/cooktop.d.ts +0 -60
  110. package/dist/devices/cooktop.d.ts.map +0 -1
  111. package/dist/devices/cooktop.js.map +0 -1
  112. package/dist/devices/dishwasher.d.ts +0 -71
  113. package/dist/devices/dishwasher.d.ts.map +0 -1
  114. package/dist/devices/dishwasher.js.map +0 -1
  115. package/dist/devices/evse.d.ts +0 -76
  116. package/dist/devices/evse.d.ts.map +0 -1
  117. package/dist/devices/evse.js.map +0 -1
  118. package/dist/devices/export.d.ts +0 -17
  119. package/dist/devices/export.d.ts.map +0 -1
  120. package/dist/devices/export.js.map +0 -1
  121. package/dist/devices/extractorHood.d.ts +0 -46
  122. package/dist/devices/extractorHood.d.ts.map +0 -1
  123. package/dist/devices/extractorHood.js.map +0 -1
  124. package/dist/devices/heatPump.d.ts +0 -47
  125. package/dist/devices/heatPump.d.ts.map +0 -1
  126. package/dist/devices/heatPump.js.map +0 -1
  127. package/dist/devices/laundryDryer.d.ts +0 -67
  128. package/dist/devices/laundryDryer.d.ts.map +0 -1
  129. package/dist/devices/laundryDryer.js.map +0 -1
  130. package/dist/devices/laundryWasher.d.ts +0 -81
  131. package/dist/devices/laundryWasher.d.ts.map +0 -1
  132. package/dist/devices/laundryWasher.js.map +0 -1
  133. package/dist/devices/microwaveOven.d.ts +0 -168
  134. package/dist/devices/microwaveOven.d.ts.map +0 -1
  135. package/dist/devices/microwaveOven.js.map +0 -1
  136. package/dist/devices/oven.d.ts +0 -105
  137. package/dist/devices/oven.d.ts.map +0 -1
  138. package/dist/devices/oven.js.map +0 -1
  139. package/dist/devices/refrigerator.d.ts +0 -118
  140. package/dist/devices/refrigerator.d.ts.map +0 -1
  141. package/dist/devices/refrigerator.js.map +0 -1
  142. package/dist/devices/roboticVacuumCleaner.d.ts +0 -112
  143. package/dist/devices/roboticVacuumCleaner.d.ts.map +0 -1
  144. package/dist/devices/roboticVacuumCleaner.js.map +0 -1
  145. package/dist/devices/solarPower.d.ts +0 -40
  146. package/dist/devices/solarPower.d.ts.map +0 -1
  147. package/dist/devices/solarPower.js.map +0 -1
  148. package/dist/devices/speaker.d.ts +0 -87
  149. package/dist/devices/speaker.d.ts.map +0 -1
  150. package/dist/devices/speaker.js.map +0 -1
  151. package/dist/devices/temperatureControl.d.ts +0 -166
  152. package/dist/devices/temperatureControl.d.ts.map +0 -1
  153. package/dist/devices/temperatureControl.js.map +0 -1
  154. package/dist/devices/waterHeater.d.ts +0 -111
  155. package/dist/devices/waterHeater.d.ts.map +0 -1
  156. package/dist/devices/waterHeater.js.map +0 -1
  157. package/dist/dgram/coap.d.ts +0 -205
  158. package/dist/dgram/coap.d.ts.map +0 -1
  159. package/dist/dgram/coap.js.map +0 -1
  160. package/dist/dgram/dgram.d.ts +0 -141
  161. package/dist/dgram/dgram.d.ts.map +0 -1
  162. package/dist/dgram/dgram.js.map +0 -1
  163. package/dist/dgram/mb_coap.d.ts +0 -24
  164. package/dist/dgram/mb_coap.d.ts.map +0 -1
  165. package/dist/dgram/mb_coap.js.map +0 -1
  166. package/dist/dgram/mb_mdns.d.ts +0 -24
  167. package/dist/dgram/mb_mdns.d.ts.map +0 -1
  168. package/dist/dgram/mb_mdns.js.map +0 -1
  169. package/dist/dgram/mdns.d.ts +0 -290
  170. package/dist/dgram/mdns.d.ts.map +0 -1
  171. package/dist/dgram/mdns.js.map +0 -1
  172. package/dist/dgram/multicast.d.ts +0 -67
  173. package/dist/dgram/multicast.d.ts.map +0 -1
  174. package/dist/dgram/multicast.js.map +0 -1
  175. package/dist/dgram/unicast.d.ts +0 -56
  176. package/dist/dgram/unicast.d.ts.map +0 -1
  177. package/dist/dgram/unicast.js.map +0 -1
  178. package/dist/frontend.d.ts +0 -235
  179. package/dist/frontend.d.ts.map +0 -1
  180. package/dist/frontend.js.map +0 -1
  181. package/dist/frontendTypes.d.ts +0 -529
  182. package/dist/frontendTypes.d.ts.map +0 -1
  183. package/dist/frontendTypes.js.map +0 -1
  184. package/dist/helpers.d.ts +0 -48
  185. package/dist/helpers.d.ts.map +0 -1
  186. package/dist/helpers.js.map +0 -1
  187. package/dist/index.d.ts +0 -33
  188. package/dist/index.d.ts.map +0 -1
  189. package/dist/index.js.map +0 -1
  190. package/dist/logger/export.d.ts +0 -2
  191. package/dist/logger/export.d.ts.map +0 -1
  192. package/dist/logger/export.js.map +0 -1
  193. package/dist/matter/behaviors.d.ts +0 -2
  194. package/dist/matter/behaviors.d.ts.map +0 -1
  195. package/dist/matter/behaviors.js.map +0 -1
  196. package/dist/matter/clusters.d.ts +0 -2
  197. package/dist/matter/clusters.d.ts.map +0 -1
  198. package/dist/matter/clusters.js.map +0 -1
  199. package/dist/matter/devices.d.ts +0 -2
  200. package/dist/matter/devices.d.ts.map +0 -1
  201. package/dist/matter/devices.js.map +0 -1
  202. package/dist/matter/endpoints.d.ts +0 -2
  203. package/dist/matter/endpoints.d.ts.map +0 -1
  204. package/dist/matter/endpoints.js.map +0 -1
  205. package/dist/matter/export.d.ts +0 -5
  206. package/dist/matter/export.d.ts.map +0 -1
  207. package/dist/matter/export.js.map +0 -1
  208. package/dist/matter/types.d.ts +0 -3
  209. package/dist/matter/types.d.ts.map +0 -1
  210. package/dist/matter/types.js.map +0 -1
  211. package/dist/matterbridge.d.ts +0 -475
  212. package/dist/matterbridge.d.ts.map +0 -1
  213. package/dist/matterbridge.js.map +0 -1
  214. package/dist/matterbridgeAccessoryPlatform.d.ts +0 -42
  215. package/dist/matterbridgeAccessoryPlatform.d.ts.map +0 -1
  216. package/dist/matterbridgeAccessoryPlatform.js.map +0 -1
  217. package/dist/matterbridgeBehaviors.d.ts +0 -2404
  218. package/dist/matterbridgeBehaviors.d.ts.map +0 -1
  219. package/dist/matterbridgeBehaviors.js.map +0 -1
  220. package/dist/matterbridgeDeviceTypes.d.ts +0 -770
  221. package/dist/matterbridgeDeviceTypes.d.ts.map +0 -1
  222. package/dist/matterbridgeDeviceTypes.js.map +0 -1
  223. package/dist/matterbridgeDynamicPlatform.d.ts +0 -42
  224. package/dist/matterbridgeDynamicPlatform.d.ts.map +0 -1
  225. package/dist/matterbridgeDynamicPlatform.js.map +0 -1
  226. package/dist/matterbridgeEndpoint.d.ts +0 -1550
  227. package/dist/matterbridgeEndpoint.d.ts.map +0 -1
  228. package/dist/matterbridgeEndpoint.js.map +0 -1
  229. package/dist/matterbridgeEndpointHelpers.d.ts +0 -758
  230. package/dist/matterbridgeEndpointHelpers.d.ts.map +0 -1
  231. package/dist/matterbridgeEndpointHelpers.js.map +0 -1
  232. package/dist/matterbridgePlatform.d.ts +0 -402
  233. package/dist/matterbridgePlatform.d.ts.map +0 -1
  234. package/dist/matterbridgePlatform.js.map +0 -1
  235. package/dist/matterbridgeTypes.d.ts +0 -226
  236. package/dist/matterbridgeTypes.d.ts.map +0 -1
  237. package/dist/matterbridgeTypes.js.map +0 -1
  238. package/dist/pluginManager.d.ts +0 -347
  239. package/dist/pluginManager.d.ts.map +0 -1
  240. package/dist/pluginManager.js.map +0 -1
  241. package/dist/shelly.d.ts +0 -174
  242. package/dist/shelly.d.ts.map +0 -1
  243. package/dist/shelly.js.map +0 -1
  244. package/dist/storage/export.d.ts +0 -2
  245. package/dist/storage/export.d.ts.map +0 -1
  246. package/dist/storage/export.js.map +0 -1
  247. package/dist/update.d.ts +0 -75
  248. package/dist/update.d.ts.map +0 -1
  249. package/dist/update.js.map +0 -1
  250. package/dist/utils/colorUtils.d.ts +0 -99
  251. package/dist/utils/colorUtils.d.ts.map +0 -1
  252. package/dist/utils/colorUtils.js.map +0 -1
  253. package/dist/utils/commandLine.d.ts +0 -66
  254. package/dist/utils/commandLine.d.ts.map +0 -1
  255. package/dist/utils/commandLine.js.map +0 -1
  256. package/dist/utils/copyDirectory.d.ts +0 -33
  257. package/dist/utils/copyDirectory.d.ts.map +0 -1
  258. package/dist/utils/copyDirectory.js.map +0 -1
  259. package/dist/utils/createDirectory.d.ts +0 -34
  260. package/dist/utils/createDirectory.d.ts.map +0 -1
  261. package/dist/utils/createDirectory.js.map +0 -1
  262. package/dist/utils/createZip.d.ts +0 -39
  263. package/dist/utils/createZip.d.ts.map +0 -1
  264. package/dist/utils/createZip.js.map +0 -1
  265. package/dist/utils/deepCopy.d.ts +0 -32
  266. package/dist/utils/deepCopy.d.ts.map +0 -1
  267. package/dist/utils/deepCopy.js.map +0 -1
  268. package/dist/utils/deepEqual.d.ts +0 -54
  269. package/dist/utils/deepEqual.d.ts.map +0 -1
  270. package/dist/utils/deepEqual.js.map +0 -1
  271. package/dist/utils/error.d.ts +0 -44
  272. package/dist/utils/error.d.ts.map +0 -1
  273. package/dist/utils/error.js.map +0 -1
  274. package/dist/utils/export.d.ts +0 -13
  275. package/dist/utils/export.d.ts.map +0 -1
  276. package/dist/utils/export.js.map +0 -1
  277. package/dist/utils/format.d.ts +0 -53
  278. package/dist/utils/format.d.ts.map +0 -1
  279. package/dist/utils/format.js.map +0 -1
  280. package/dist/utils/hex.d.ts +0 -89
  281. package/dist/utils/hex.d.ts.map +0 -1
  282. package/dist/utils/hex.js.map +0 -1
  283. package/dist/utils/inspector.d.ts +0 -87
  284. package/dist/utils/inspector.d.ts.map +0 -1
  285. package/dist/utils/inspector.js.map +0 -1
  286. package/dist/utils/isvalid.d.ts +0 -103
  287. package/dist/utils/isvalid.d.ts.map +0 -1
  288. package/dist/utils/isvalid.js.map +0 -1
  289. package/dist/utils/jestHelpers.d.ts +0 -139
  290. package/dist/utils/jestHelpers.d.ts.map +0 -1
  291. package/dist/utils/jestHelpers.js.map +0 -1
  292. package/dist/utils/network.d.ts +0 -101
  293. package/dist/utils/network.d.ts.map +0 -1
  294. package/dist/utils/network.js.map +0 -1
  295. package/dist/utils/spawn.d.ts +0 -35
  296. package/dist/utils/spawn.d.ts.map +0 -1
  297. package/dist/utils/spawn.js.map +0 -1
  298. package/dist/utils/tracker.d.ts +0 -108
  299. package/dist/utils/tracker.d.ts.map +0 -1
  300. package/dist/utils/tracker.js.map +0 -1
  301. package/dist/utils/wait.d.ts +0 -54
  302. package/dist/utils/wait.d.ts.map +0 -1
  303. package/dist/utils/wait.js.map +0 -1
package/dist/frontend.js CHANGED
@@ -1,34 +1,8 @@
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
- // Node modules
28
3
  import os from 'node:os';
29
4
  import path from 'node:path';
30
5
  import EventEmitter from 'node:events';
31
- // AnsiLogger module
32
6
  import { AnsiLogger, stringify, debugStringify, CYAN, db, er, nf, rs, UNDERLINE, UNDERLINEOFF, YELLOW, nt } from 'node-ansi-logger';
33
7
  import { Logger, Diagnostic, LogDestination, LogLevel as MatterLogLevel, LogFormat as MatterLogFormat, Lifecycle } from '@matter/general';
34
8
  import { DeviceAdvertiser, DeviceCommissioner, FabricManager } from '@matter/protocol';
@@ -60,7 +34,7 @@ export class Frontend extends EventEmitter {
60
34
  constructor(matterbridge) {
61
35
  super();
62
36
  this.matterbridge = matterbridge;
63
- this.log = new AnsiLogger({ logName: 'Frontend', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: hasParameter('debug') ? "debug" /* LogLevel.DEBUG */ : "info" /* LogLevel.INFO */ });
37
+ this.log = new AnsiLogger({ logName: 'Frontend', logTimestampFormat: 4, logLevel: hasParameter('debug') ? "debug" : "info" });
64
38
  this.log.logNameColor = '\x1b[38;5;97m';
65
39
  this.server = new BroadcastServer('frontend', this.log);
66
40
  this.server.on('broadcast_message', this.msgHandler.bind(this));
@@ -120,42 +94,13 @@ export class Frontend extends EventEmitter {
120
94
  async start(port = 8283) {
121
95
  this.port = port;
122
96
  this.log.debug(`Initializing the frontend ${hasParameter('ssl') ? 'https' : 'http'} server on port ${YELLOW}${this.port}${db}`);
123
- // Initialize multer with the upload directory
124
97
  const multer = await import('multer');
125
- const uploadDir = path.join(this.matterbridge.matterbridgeDirectory, 'uploads'); // Is created by matterbridge initialize
98
+ const uploadDir = path.join(this.matterbridge.matterbridgeDirectory, 'uploads');
126
99
  const upload = multer.default({ dest: uploadDir });
127
- // Create the express app that serves the frontend
128
100
  const express = await import('express');
129
101
  this.expressApp = express.default();
130
- // Inject logging/debug wrapper for route/middleware registration
131
- /*
132
- const methods = ['get', 'post', 'put', 'delete', 'use'];
133
- for (const method of methods) {
134
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
135
- const original = (this.expressApp as any)[method].bind(this.expressApp);
136
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
137
- (this.expressApp as any)[method] = (path: any, ...rest: any) => {
138
- try {
139
- console.log(`[DEBUG] Registering ${method.toUpperCase()} route:`, path);
140
- return original(path, ...rest);
141
- } catch (err) {
142
- console.error(`[ERROR] Failed to register route: ${path}`);
143
- throw err;
144
- }
145
- };
146
- }
147
- */
148
- // Log all requests to the server for debugging
149
- /*
150
- this.expressApp.use((req, res, next) => {
151
- this.log.debug(`***Received request on expressApp: ${req.method} ${req.url}`);
152
- next();
153
- });
154
- */
155
- // Serve static files from 'frontend/build' directory
156
102
  this.expressApp.use(express.static(path.join(this.matterbridge.rootDirectory, 'frontend/build')));
157
103
  if (!hasParameter('ssl')) {
158
- // Create an HTTP server and attach the express app
159
104
  const http = await import('node:http');
160
105
  try {
161
106
  this.log.debug(`Creating HTTP server...`);
@@ -166,7 +111,6 @@ export class Frontend extends EventEmitter {
166
111
  this.emit('server_error', error);
167
112
  return;
168
113
  }
169
- // Listen on the specified port
170
114
  if (hasParameter('ingress')) {
171
115
  this.httpServer.listen(this.port, '0.0.0.0', () => {
172
116
  this.log.info(`The frontend http server is listening on ${UNDERLINE}http://0.0.0.0:${this.port}${UNDERLINEOFF}${rs}`);
@@ -199,7 +143,6 @@ export class Frontend extends EventEmitter {
199
143
  });
200
144
  }
201
145
  else {
202
- // SSL is enabled, load the certificate and the private key
203
146
  let cert;
204
147
  let key;
205
148
  let ca;
@@ -209,7 +152,6 @@ export class Frontend extends EventEmitter {
209
152
  let httpsServerOptions = {};
210
153
  const fs = await import('node:fs');
211
154
  if (fs.existsSync(path.join(this.matterbridge.matterbridgeDirectory, 'certs/cert.p12'))) {
212
- // Load the p12 certificate and the passphrase
213
155
  try {
214
156
  pfx = await fs.promises.readFile(path.join(this.matterbridge.matterbridgeDirectory, 'certs/cert.p12'));
215
157
  this.log.info(`Loaded p12 certificate file ${path.join(this.matterbridge.matterbridgeDirectory, 'certs/cert.p12')}`);
@@ -221,7 +163,7 @@ export class Frontend extends EventEmitter {
221
163
  }
222
164
  try {
223
165
  passphrase = await fs.promises.readFile(path.join(this.matterbridge.matterbridgeDirectory, 'certs/cert.pass'), 'utf8');
224
- passphrase = passphrase.trim(); // Ensure no extra characters
166
+ passphrase = passphrase.trim();
225
167
  this.log.info(`Loaded p12 passphrase file ${path.join(this.matterbridge.matterbridgeDirectory, 'certs/cert.pass')}`);
226
168
  }
227
169
  catch (error) {
@@ -232,7 +174,6 @@ export class Frontend extends EventEmitter {
232
174
  httpsServerOptions = { pfx, passphrase };
233
175
  }
234
176
  else {
235
- // 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.
236
177
  try {
237
178
  cert = await fs.promises.readFile(path.join(this.matterbridge.matterbridgeDirectory, 'certs/cert.pem'), 'utf8');
238
179
  this.log.info(`Loaded certificate file ${path.join(this.matterbridge.matterbridgeDirectory, 'certs/cert.pem')}`);
@@ -262,10 +203,9 @@ export class Frontend extends EventEmitter {
262
203
  httpsServerOptions = { cert: fullChain ?? cert, key, ca };
263
204
  }
264
205
  if (hasParameter('mtls')) {
265
- httpsServerOptions.requestCert = true; // Request client certificate
266
- httpsServerOptions.rejectUnauthorized = true; // Require client certificate validation
206
+ httpsServerOptions.requestCert = true;
207
+ httpsServerOptions.rejectUnauthorized = true;
267
208
  }
268
- // Create an HTTPS server with the SSL certificate and private key (ca is optional) and attach the express app
269
209
  const https = await import('node:https');
270
210
  try {
271
211
  this.log.debug(`Creating HTTPS server...`);
@@ -276,7 +216,6 @@ export class Frontend extends EventEmitter {
276
216
  this.emit('server_error', error);
277
217
  return;
278
218
  }
279
- // Listen on the specified port
280
219
  if (hasParameter('ingress')) {
281
220
  this.httpsServer.listen(this.port, '0.0.0.0', () => {
282
221
  this.log.info(`The frontend https server is listening on ${UNDERLINE}https://0.0.0.0:${this.port}${UNDERLINEOFF}${rs}`);
@@ -308,41 +247,16 @@ export class Frontend extends EventEmitter {
308
247
  return;
309
248
  });
310
249
  }
311
- // Load the stored password
312
- /*
313
- let storedPassword = '';
314
- try {
315
- if (!this.matterbridge.nodeContext) throw new Error('nodeContext not found');
316
- storedPassword = await this.matterbridge.nodeContext.get('password', '');
317
- } catch (error) {
318
- inspectError(this.log, 'Error getting password', error);
319
- return;
320
- }
321
- */
322
- // Create a WebSocket server and attach it to the http or https server
323
250
  const ws = await import('ws');
324
251
  this.log.debug(`Creating WebSocketServer...`);
325
252
  this.webSocketServer = new ws.WebSocketServer(hasParameter('ssl') ? { server: this.httpsServer } : { server: this.httpServer });
326
253
  this.webSocketServer.on('connection', (ws, request) => {
327
254
  const clientIp = request.socket.remoteAddress;
328
- /*
329
- if (storedPassword !== '') {
330
- // Check for the password in the query parameters
331
- const url = new URL(request.url ?? '', `http://${request.headers.host}`);
332
- const password = url.searchParams.get('password');
333
- if (password !== storedPassword) {
334
- this.log.error(`WebSocket client "${clientIp}" failed authentication: ${storedPassword}-${password}`);
335
- // ws.close();
336
- // return;
337
- }
338
- }
339
- */
340
- // Set the global logger callback for the WebSocketServer
341
- let callbackLogLevel = "notice" /* LogLevel.NOTICE */;
342
- if (this.matterbridge.getLogLevel() === "info" /* LogLevel.INFO */ || Logger.level === MatterLogLevel.INFO)
343
- callbackLogLevel = "info" /* LogLevel.INFO */;
344
- if (this.matterbridge.getLogLevel() === "debug" /* LogLevel.DEBUG */ || Logger.level === MatterLogLevel.DEBUG)
345
- callbackLogLevel = "debug" /* LogLevel.DEBUG */;
255
+ let callbackLogLevel = "notice";
256
+ if (this.matterbridge.getLogLevel() === "info" || Logger.level === MatterLogLevel.INFO)
257
+ callbackLogLevel = "info";
258
+ if (this.matterbridge.getLogLevel() === "debug" || Logger.level === MatterLogLevel.DEBUG)
259
+ callbackLogLevel = "debug";
346
260
  AnsiLogger.setGlobalCallback(this.wssSendLogMessage.bind(this), callbackLogLevel);
347
261
  this.log.debug(`WebSocketServer logger global callback set to ${callbackLogLevel}`);
348
262
  this.log.info(`WebSocketServer client "${clientIp}" connected to Matterbridge`);
@@ -364,7 +278,6 @@ export class Frontend extends EventEmitter {
364
278
  }
365
279
  });
366
280
  ws.on('error', (error) => {
367
- // istanbul ignore next
368
281
  this.log.error(`WebSocket client error: ${error}`);
369
282
  });
370
283
  });
@@ -378,7 +291,6 @@ export class Frontend extends EventEmitter {
378
291
  this.webSocketServer.on('error', (ws, error) => {
379
292
  this.log.error(`WebSocketServer error: ${error}`);
380
293
  });
381
- // Subscribe to cli events
382
294
  cliEmitter.removeAllListeners();
383
295
  cliEmitter.on('uptime', (systemUptime, processUptime) => {
384
296
  this.wssSendUptimeUpdate(systemUptime, processUptime);
@@ -389,8 +301,6 @@ export class Frontend extends EventEmitter {
389
301
  cliEmitter.on('cpu', (cpuUsage, processCpuUsage) => {
390
302
  this.wssSendCpuUpdate(cpuUsage, processCpuUsage);
391
303
  });
392
- // Endpoint to validate login code
393
- // curl -X POST "http://localhost:8283/api/login" -H "Content-Type: application/json" -d "{\"password\":\"Here\"}"
394
304
  this.expressApp.post('/api/login', express.json(), async (req, res) => {
395
305
  const { password } = req.body;
396
306
  this.log.debug('The frontend sent /api/login', password);
@@ -409,27 +319,23 @@ export class Frontend extends EventEmitter {
409
319
  this.log.warn('/api/login error wrong password');
410
320
  res.json({ valid: false });
411
321
  }
412
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
413
322
  }
414
323
  catch (error) {
415
324
  this.log.error('/api/login error getting password');
416
325
  res.json({ valid: false });
417
326
  }
418
327
  });
419
- // Endpoint to provide health check for docker
420
328
  this.expressApp.get('/health', (req, res) => {
421
329
  this.log.debug('Express received /health');
422
330
  const healthStatus = {
423
- status: 'ok', // Indicate service is healthy
424
- uptime: process.uptime(), // Server uptime in seconds
425
- timestamp: new Date().toISOString(), // Current timestamp
331
+ status: 'ok',
332
+ uptime: process.uptime(),
333
+ timestamp: new Date().toISOString(),
426
334
  };
427
335
  res.status(200).json(healthStatus);
428
336
  });
429
- // Endpoint to provide memory usage details
430
337
  this.expressApp.get('/memory', async (req, res) => {
431
338
  this.log.debug('Express received /memory');
432
- // Memory usage from process
433
339
  const memoryUsageRaw = process.memoryUsage();
434
340
  const memoryUsage = {
435
341
  rss: formatBytes(memoryUsageRaw.rss),
@@ -438,13 +344,10 @@ export class Frontend extends EventEmitter {
438
344
  external: formatBytes(memoryUsageRaw.external),
439
345
  arrayBuffers: formatBytes(memoryUsageRaw.arrayBuffers),
440
346
  };
441
- // V8 heap statistics
442
347
  const { default: v8 } = await import('node:v8');
443
348
  const heapStatsRaw = v8.getHeapStatistics();
444
349
  const heapSpacesRaw = v8.getHeapSpaceStatistics();
445
- // Format heapStats
446
350
  const heapStats = Object.fromEntries(Object.entries(heapStatsRaw).map(([key, value]) => [key, formatBytes(value)]));
447
- // Format heapSpaces
448
351
  const heapSpaces = heapSpacesRaw.map((space) => ({
449
352
  ...space,
450
353
  space_size: formatBytes(space.space_size),
@@ -463,22 +366,18 @@ export class Frontend extends EventEmitter {
463
366
  };
464
367
  res.status(200).json(memoryReport);
465
368
  });
466
- // Endpoint to provide settings
467
369
  this.expressApp.get('/api/settings', express.json(), async (req, res) => {
468
370
  this.log.debug('The frontend sent /api/settings');
469
371
  res.json(await this.getApiSettings());
470
372
  });
471
- // Endpoint to provide plugins
472
373
  this.expressApp.get('/api/plugins', async (req, res) => {
473
374
  this.log.debug('The frontend sent /api/plugins');
474
375
  res.json(this.matterbridge.hasCleanupStarted ? [] : this.getPlugins());
475
376
  });
476
- // Endpoint to provide devices
477
377
  this.expressApp.get('/api/devices', async (req, res) => {
478
378
  this.log.debug('The frontend sent /api/devices');
479
379
  res.json(this.matterbridge.hasCleanupStarted ? [] : this.getDevices());
480
380
  });
481
- // Endpoint to view the matterbridge log
482
381
  this.expressApp.get('/api/view-mblog', async (req, res) => {
483
382
  this.log.debug('The frontend sent /api/view-mblog');
484
383
  try {
@@ -492,7 +391,6 @@ export class Frontend extends EventEmitter {
492
391
  res.status(500).send('Error reading matterbridge log file. Please enable the matterbridge log on file in the settings.');
493
392
  }
494
393
  });
495
- // Endpoint to view the matter.js log
496
394
  this.expressApp.get('/api/view-mjlog', async (req, res) => {
497
395
  this.log.debug('The frontend sent /api/view-mjlog');
498
396
  try {
@@ -506,7 +404,6 @@ export class Frontend extends EventEmitter {
506
404
  res.status(500).send('Error reading matter log file. Please enable the matter log on file in the settings.');
507
405
  }
508
406
  });
509
- // Endpoint to view the diagnostic.log
510
407
  this.expressApp.get('/api/view-diagnostic', async (req, res) => {
511
408
  this.log.debug('The frontend sent /api/view-diagnostic');
512
409
  await this.generateDiagnostic();
@@ -517,13 +414,10 @@ export class Frontend extends EventEmitter {
517
414
  res.send(data.slice(29));
518
415
  }
519
416
  catch (error) {
520
- // istanbul ignore next
521
417
  this.log.error(`Error reading diagnostic log file ${MATTERBRIDGE_DIAGNOSTIC_FILE}: ${error instanceof Error ? error.message : error}`);
522
- // istanbul ignore next
523
418
  res.status(500).send('Error reading diagnostic log file.');
524
419
  }
525
420
  });
526
- // Endpoint to download the diagnostic.log
527
421
  this.expressApp.get('/api/download-diagnostic', async (req, res) => {
528
422
  this.log.debug(`The frontend sent /api/download-diagnostic`);
529
423
  await this.generateDiagnostic();
@@ -534,19 +428,16 @@ export class Frontend extends EventEmitter {
534
428
  await fs.promises.writeFile(path.join(os.tmpdir(), MATTERBRIDGE_DIAGNOSTIC_FILE), data, 'utf-8');
535
429
  }
536
430
  catch (error) {
537
- // istanbul ignore next
538
431
  this.log.debug(`Error in /api/download-diagnostic: ${error instanceof Error ? error.message : error}`);
539
432
  }
540
433
  res.type('text/plain');
541
434
  res.download(path.join(os.tmpdir(), MATTERBRIDGE_DIAGNOSTIC_FILE), MATTERBRIDGE_DIAGNOSTIC_FILE, (error) => {
542
- /* istanbul ignore if */
543
435
  if (error) {
544
436
  this.log.error(`Error downloading file ${MATTERBRIDGE_DIAGNOSTIC_FILE}: ${error instanceof Error ? error.message : error}`);
545
437
  res.status(500).send('Error downloading the diagnostic log file');
546
438
  }
547
439
  });
548
440
  });
549
- // Endpoint to view the history.html
550
441
  this.expressApp.get('/api/viewhistory', async (req, res) => {
551
442
  this.log.debug('The frontend sent /api/viewhistory');
552
443
  try {
@@ -560,7 +451,6 @@ export class Frontend extends EventEmitter {
560
451
  res.status(500).send('Error reading history file.');
561
452
  }
562
453
  });
563
- // Endpoint to download the history.html
564
454
  this.expressApp.get('/api/downloadhistory', async (req, res) => {
565
455
  this.log.debug(`The frontend sent /api/downloadhistory`);
566
456
  try {
@@ -570,7 +460,6 @@ export class Frontend extends EventEmitter {
570
460
  await fs.promises.writeFile(path.join(os.tmpdir(), MATTERBRIDGE_HISTORY_FILE), data, 'utf-8');
571
461
  res.type('text/plain');
572
462
  res.download(path.join(os.tmpdir(), MATTERBRIDGE_HISTORY_FILE), MATTERBRIDGE_HISTORY_FILE, (error) => {
573
- /* istanbul ignore if */
574
463
  if (error) {
575
464
  this.log.error(`Error in /api/downloadhistory downloading history file ${MATTERBRIDGE_HISTORY_FILE}: ${error instanceof Error ? error.message : error}`);
576
465
  res.status(500).send('Error downloading history file');
@@ -582,7 +471,6 @@ export class Frontend extends EventEmitter {
582
471
  res.status(500).send('Error reading history file.');
583
472
  }
584
473
  });
585
- // Endpoint to view the shelly log
586
474
  this.expressApp.get('/api/shellyviewsystemlog', async (req, res) => {
587
475
  this.log.debug('The frontend sent /api/shellyviewsystemlog');
588
476
  try {
@@ -596,7 +484,6 @@ export class Frontend extends EventEmitter {
596
484
  res.status(500).send('Error reading shelly log file. Please create the shelly system log before loading it.');
597
485
  }
598
486
  });
599
- // Endpoint to download the matterbridge log
600
487
  this.expressApp.get('/api/download-mblog', async (req, res) => {
601
488
  this.log.debug(`The frontend sent /api/download-mblog ${path.join(this.matterbridge.matterbridgeDirectory, MATTERBRIDGE_LOGGER_FILE)}`);
602
489
  const fs = await import('node:fs');
@@ -611,14 +498,12 @@ export class Frontend extends EventEmitter {
611
498
  }
612
499
  res.type('text/plain');
613
500
  res.download(path.join(os.tmpdir(), MATTERBRIDGE_LOGGER_FILE), 'matterbridge.log', (error) => {
614
- /* istanbul ignore if */
615
501
  if (error) {
616
502
  this.log.error(`Error downloading log file ${MATTERBRIDGE_LOGGER_FILE}: ${error instanceof Error ? error.message : error}`);
617
503
  res.status(500).send('Error downloading the matterbridge log file');
618
504
  }
619
505
  });
620
506
  });
621
- // Endpoint to download the matter log
622
507
  this.expressApp.get('/api/download-mjlog', async (req, res) => {
623
508
  this.log.debug(`The frontend sent /api/download-mjlog ${path.join(this.matterbridge.matterbridgeDirectory, MATTERBRIDGE_LOGGER_FILE)}`);
624
509
  const fs = await import('node:fs');
@@ -633,14 +518,12 @@ export class Frontend extends EventEmitter {
633
518
  }
634
519
  res.type('text/plain');
635
520
  res.download(path.join(os.tmpdir(), MATTER_LOGGER_FILE), 'matter.log', (error) => {
636
- /* istanbul ignore if */
637
521
  if (error) {
638
522
  this.log.error(`Error downloading log file ${MATTER_LOGGER_FILE}: ${error instanceof Error ? error.message : error}`);
639
523
  res.status(500).send('Error downloading the matter log file');
640
524
  }
641
525
  });
642
526
  });
643
- // Endpoint to download the shelly log
644
527
  this.expressApp.get('/api/shellydownloadsystemlog', async (req, res) => {
645
528
  this.log.debug('The frontend sent /api/shellydownloadsystemlog');
646
529
  const fs = await import('node:fs');
@@ -655,91 +538,75 @@ export class Frontend extends EventEmitter {
655
538
  }
656
539
  res.type('text/plain');
657
540
  res.download(path.join(os.tmpdir(), 'shelly.log'), 'shelly.log', (error) => {
658
- /* istanbul ignore if */
659
541
  if (error) {
660
542
  this.log.error(`Error downloading Shelly system log file: ${error instanceof Error ? error.message : error}`);
661
543
  res.status(500).send('Error downloading Shelly system log file');
662
544
  }
663
545
  });
664
546
  });
665
- // Endpoint to download the matterbridge storage directory
666
547
  this.expressApp.get('/api/download-mbstorage', async (req, res) => {
667
548
  this.log.debug('The frontend sent /api/download-mbstorage');
668
549
  await createZip(path.join(os.tmpdir(), `matterbridge.${NODE_STORAGE_DIR}.zip`), path.join(this.matterbridge.matterbridgeDirectory, NODE_STORAGE_DIR));
669
550
  res.download(path.join(os.tmpdir(), `matterbridge.${NODE_STORAGE_DIR}.zip`), `matterbridge.${NODE_STORAGE_DIR}.zip`, (error) => {
670
- /* istanbul ignore if */
671
551
  if (error) {
672
552
  this.log.error(`Error downloading file ${`matterbridge.${NODE_STORAGE_DIR}.zip`}: ${error instanceof Error ? error.message : error}`);
673
553
  res.status(500).send('Error downloading the matterbridge storage file');
674
554
  }
675
555
  });
676
556
  });
677
- // Endpoint to download the matter storage file
678
557
  this.expressApp.get('/api/download-mjstorage', async (req, res) => {
679
558
  this.log.debug('The frontend sent /api/download-mjstorage');
680
559
  await createZip(path.join(os.tmpdir(), `matterbridge.${MATTER_STORAGE_NAME}.zip`), path.join(this.matterbridge.matterbridgeDirectory, MATTER_STORAGE_NAME));
681
560
  res.download(path.join(os.tmpdir(), `matterbridge.${MATTER_STORAGE_NAME}.zip`), `matterbridge.${MATTER_STORAGE_NAME}.zip`, (error) => {
682
- /* istanbul ignore if */
683
561
  if (error) {
684
562
  this.log.error(`Error downloading the matter storage matterbridge.${MATTER_STORAGE_NAME}.zip: ${error instanceof Error ? error.message : error}`);
685
563
  res.status(500).send('Error downloading the matter storage zip file');
686
564
  }
687
565
  });
688
566
  });
689
- // Endpoint to download the matterbridge plugin directory
690
567
  this.expressApp.get('/api/download-pluginstorage', async (req, res) => {
691
568
  this.log.debug('The frontend sent /api/download-pluginstorage');
692
569
  await createZip(path.join(os.tmpdir(), `matterbridge.pluginstorage.zip`), this.matterbridge.matterbridgePluginDirectory);
693
570
  res.download(path.join(os.tmpdir(), `matterbridge.pluginstorage.zip`), `matterbridge.pluginstorage.zip`, (error) => {
694
- /* istanbul ignore if */
695
571
  if (error) {
696
572
  this.log.error(`Error downloading file matterbridge.pluginstorage.zip: ${error instanceof Error ? error.message : error}`);
697
573
  res.status(500).send('Error downloading the matterbridge plugin storage file');
698
574
  }
699
575
  });
700
576
  });
701
- // Endpoint to download the matterbridge plugin config files
702
577
  this.expressApp.get('/api/download-pluginconfig', async (req, res) => {
703
578
  this.log.debug('The frontend sent /api/download-pluginconfig');
704
579
  await createZip(path.join(os.tmpdir(), `matterbridge.pluginconfig.zip`), path.relative(process.cwd(), path.join(this.matterbridge.matterbridgeDirectory, '*.config.json')));
705
580
  res.download(path.join(os.tmpdir(), `matterbridge.pluginconfig.zip`), `matterbridge.pluginconfig.zip`, (error) => {
706
- /* istanbul ignore if */
707
581
  if (error) {
708
582
  this.log.error(`Error downloading file matterbridge.pluginconfig.zip: ${error instanceof Error ? error.message : error}`);
709
583
  res.status(500).send('Error downloading the matterbridge plugin config file');
710
584
  }
711
585
  });
712
586
  });
713
- // Endpoint to download the matterbridge backup (created with the backup command)
714
587
  this.expressApp.get('/api/download-backup', async (req, res) => {
715
588
  this.log.debug('The frontend sent /api/download-backup');
716
589
  res.download(path.join(os.tmpdir(), `matterbridge.backup.zip`), `matterbridge.backup.zip`, (error) => {
717
- /* istanbul ignore if */
718
590
  if (error) {
719
591
  this.log.error(`Error downloading file matterbridge.backup.zip: ${error instanceof Error ? error.message : error}`);
720
592
  res.status(500).send(`Error downloading file matterbridge.backup.zip: ${error instanceof Error ? error.message : error}`);
721
593
  }
722
594
  });
723
595
  });
724
- // Endpoint to upload a package
725
596
  this.expressApp.post('/api/uploadpackage', upload.single('file'), async (req, res) => {
726
597
  const { filename } = req.body;
727
598
  const file = req.file;
728
- /* istanbul ignore if */
729
599
  if (!file || !filename) {
730
600
  this.log.error(`uploadpackage: invalid request: file and filename are required`);
731
601
  res.status(400).send('Invalid request: file and filename are required');
732
602
  return;
733
603
  }
734
604
  this.wssSendSnackbarMessage(`Installing package ${filename}. Please wait...`, 0);
735
- // Define the path where the plugin file will be saved
736
605
  const filePath = path.join(this.matterbridge.matterbridgeDirectory, 'uploads', filename);
737
606
  try {
738
- // Move the uploaded file to the specified path
739
607
  const fs = await import('node:fs');
740
608
  await fs.promises.rename(file.path, filePath);
741
609
  this.log.info(`File ${plg}${filename}${nf} uploaded successfully`);
742
- // Install the plugin package
743
610
  if (filename.endsWith('.tgz')) {
744
611
  const { spawnCommand } = await import('./utils/spawn.js');
745
612
  await spawnCommand(this.matterbridge, 'npm', ['install', '-g', filePath, '--omit=dev', '--verbose'], 'install', filename);
@@ -759,7 +626,6 @@ export class Frontend extends EventEmitter {
759
626
  res.status(500).send(`Error uploading or installing plugin package ${filename}`);
760
627
  }
761
628
  });
762
- // Fallback for routing (must be the last route)
763
629
  this.expressApp.use((req, res) => {
764
630
  this.log.debug(`The frontend sent ${req.url} method ${req.method}: sending index.html as fallback`);
765
631
  res.sendFile(path.join(this.matterbridge.rootDirectory, 'frontend/build/index.html'));
@@ -769,16 +635,13 @@ export class Frontend extends EventEmitter {
769
635
  async stop() {
770
636
  this.log.debug('Stopping the frontend...');
771
637
  const ws = await import('ws');
772
- // Remove listeners from the express app
773
638
  if (this.expressApp) {
774
639
  this.expressApp.removeAllListeners();
775
640
  this.expressApp = undefined;
776
641
  this.log.debug('Frontend app closed successfully');
777
642
  }
778
- // Close the WebSocket server
779
643
  if (this.webSocketServer) {
780
644
  this.log.debug('Closing WebSocket server...');
781
- // Close all active connections
782
645
  this.webSocketServer.clients.forEach((client) => {
783
646
  if (client.readyState === ws.WebSocket.OPEN) {
784
647
  client.close();
@@ -787,7 +650,6 @@ export class Frontend extends EventEmitter {
787
650
  await withTimeout(new Promise((resolve) => {
788
651
  this.webSocketServer?.close((error) => {
789
652
  if (error) {
790
- // istanbul ignore next
791
653
  this.log.error(`Error closing WebSocket server: ${error}`);
792
654
  }
793
655
  else {
@@ -800,27 +662,8 @@ export class Frontend extends EventEmitter {
800
662
  this.webSocketServer.removeAllListeners();
801
663
  this.webSocketServer = undefined;
802
664
  }
803
- // Close the http server
804
665
  if (this.httpServer) {
805
666
  this.log.debug('Closing http server...');
806
- /*
807
- await withTimeout(
808
- new Promise<void>((resolve) => {
809
- this.httpServer?.close((error) => {
810
- if (error) {
811
- // istanbul ignore next
812
- this.log.error(`Error closing http server: ${error}`);
813
- } else {
814
- this.log.debug('Http server closed successfully');
815
- this.emit('server_stopped');
816
- }
817
- resolve();
818
- });
819
- }),
820
- 5000,
821
- false,
822
- );
823
- */
824
667
  this.httpServer.close();
825
668
  this.log.debug('Http server closed successfully');
826
669
  this.listening = false;
@@ -829,27 +672,8 @@ export class Frontend extends EventEmitter {
829
672
  this.httpServer = undefined;
830
673
  this.log.debug('Frontend http server closed successfully');
831
674
  }
832
- // Close the https server
833
675
  if (this.httpsServer) {
834
676
  this.log.debug('Closing https server...');
835
- /*
836
- await withTimeout(
837
- new Promise<void>((resolve) => {
838
- this.httpsServer?.close((error) => {
839
- if (error) {
840
- // istanbul ignore next
841
- this.log.error(`Error closing https server: ${error}`);
842
- } else {
843
- this.log.debug('Https server closed successfully');
844
- this.emit('server_stopped');
845
- }
846
- resolve();
847
- });
848
- }),
849
- 5000,
850
- false,
851
- );
852
- */
853
677
  this.httpsServer.close();
854
678
  this.log.debug('Https server closed successfully');
855
679
  this.listening = false;
@@ -860,13 +684,7 @@ export class Frontend extends EventEmitter {
860
684
  }
861
685
  this.log.debug('Frontend stopped successfully');
862
686
  }
863
- /**
864
- * Retrieves the api settings data.
865
- *
866
- * @returns {Promise<{ matterbridgeInformation: MatterbridgeInformation, systemInformation: SystemInformation }>} A promise that resolve in the api settings object.
867
- */
868
687
  async getApiSettings() {
869
- // Update the variable system information properties
870
688
  this.matterbridge.systemInformation.totalMemory = formatBytes(os.totalmem());
871
689
  this.matterbridge.systemInformation.freeMemory = formatBytes(os.freemem());
872
690
  this.matterbridge.systemInformation.systemUptime = formatUptime(os.uptime());
@@ -876,7 +694,6 @@ export class Frontend extends EventEmitter {
876
694
  this.matterbridge.systemInformation.rss = formatBytes(process.memoryUsage().rss);
877
695
  this.matterbridge.systemInformation.heapTotal = formatBytes(process.memoryUsage().heapTotal);
878
696
  this.matterbridge.systemInformation.heapUsed = formatBytes(process.memoryUsage().heapUsed);
879
- // Create the matterbridge information
880
697
  const info = {
881
698
  homeDirectory: this.matterbridge.homeDirectory,
882
699
  rootDirectory: this.matterbridge.rootDirectory,
@@ -912,15 +729,9 @@ export class Frontend extends EventEmitter {
912
729
  };
913
730
  return { systemInformation: this.matterbridge.systemInformation, matterbridgeInformation: info };
914
731
  }
915
- /**
916
- * Retrieves the reachable attribute.
917
- *
918
- * @param {MatterbridgeEndpoint} device - The MatterbridgeEndpoint object.
919
- * @returns {boolean} The reachable attribute.
920
- */
921
732
  getReachability(device) {
922
733
  if (this.matterbridge.hasCleanupStarted)
923
- return false; // Skip if cleanup has started
734
+ return false;
924
735
  if (!device.lifecycle.isReady || device.construction.status !== Lifecycle.Status.Active)
925
736
  return false;
926
737
  if (device.hasClusterServer(BridgedDeviceBasicInformation.Cluster.id))
@@ -931,15 +742,9 @@ export class Frontend extends EventEmitter {
931
742
  return true;
932
743
  return false;
933
744
  }
934
- /**
935
- * Retrieves the power source attribute.
936
- *
937
- * @param {MatterbridgeEndpoint} endpoint - The MatterbridgeDevice to retrieve the power source from.
938
- * @returns {'ac' | 'dc' | 'ok' | 'warning' | 'critical' | undefined} The power source attribute.
939
- */
940
745
  getPowerSource(endpoint) {
941
746
  if (this.matterbridge.hasCleanupStarted)
942
- return; // Skip if cleanup has started
747
+ return;
943
748
  if (!endpoint.lifecycle.isReady || endpoint.construction.status !== Lifecycle.Status.Active)
944
749
  return undefined;
945
750
  const powerSource = (device) => {
@@ -954,25 +759,16 @@ export class Frontend extends EventEmitter {
954
759
  }
955
760
  return;
956
761
  };
957
- // Root endpoint
958
762
  if (endpoint.hasClusterServer(PowerSource.Cluster.id))
959
763
  return powerSource(endpoint);
960
- // Child endpoints
961
764
  for (const child of endpoint.getChildEndpoints()) {
962
765
  if (child.hasClusterServer(PowerSource.Cluster.id))
963
766
  return powerSource(child);
964
767
  }
965
768
  }
966
- /**
967
- * Retrieves the cluster text description from a given device.
968
- * The output is a string with the attributes description of the cluster servers in the device to show in the frontend.
969
- *
970
- * @param {MatterbridgeEndpoint} device - The MatterbridgeEndpoint to retrieve the cluster text from.
971
- * @returns {string} The attributes description of the cluster servers in the device.
972
- */
973
769
  getClusterTextFromDevice(device) {
974
770
  if (this.matterbridge.hasCleanupStarted)
975
- return ''; // Skip if cleanup has started
771
+ return '';
976
772
  if (!device.lifecycle.isReady || device.construction.status !== Lifecycle.Status.Active)
977
773
  return '';
978
774
  const getUserLabel = (device) => {
@@ -982,7 +778,6 @@ export class Frontend extends EventEmitter {
982
778
  if (composed)
983
779
  return 'Composed: ' + composed.value;
984
780
  }
985
- // istanbul ignore next cause is not reachable
986
781
  return '';
987
782
  };
988
783
  const getFixedLabel = (device) => {
@@ -992,13 +787,11 @@ export class Frontend extends EventEmitter {
992
787
  if (composed)
993
788
  return 'Composed: ' + composed.value;
994
789
  }
995
- // istanbul ignore next cause is not reacheable
996
790
  return '';
997
791
  };
998
792
  let attributes = '';
999
793
  let supportedModes = [];
1000
794
  device.forEachAttribute((clusterName, clusterId, attributeName, attributeId, attributeValue) => {
1001
- // console.log(`${device.deviceName} => Cluster: ${clusterName}-${clusterId} Attribute: ${attributeName}-${attributeId} Value(${typeof attributeValue}): ${attributeValue}`);
1002
795
  if (typeof attributeValue === 'undefined' || attributeValue === undefined)
1003
796
  return;
1004
797
  if (clusterName === 'onOff' && attributeName === 'onOff')
@@ -1088,17 +881,11 @@ export class Frontend extends EventEmitter {
1088
881
  if (clusterName === 'userLabel' && attributeName === 'labelList')
1089
882
  attributes += `${getUserLabel(device)} `;
1090
883
  });
1091
- // console.log(`${device.deviceName}.forEachAttribute: ${attributes}`);
1092
884
  return attributes.trimStart().trimEnd();
1093
885
  }
1094
- /**
1095
- * Retrieves the registered plugins sanitized for res.json().
1096
- *
1097
- * @returns {ApiPlugin[]} An array of BaseRegisteredPlugin.
1098
- */
1099
886
  getPlugins() {
1100
887
  if (this.matterbridge.hasCleanupStarted)
1101
- return []; // Skip if cleanup has started
888
+ return [];
1102
889
  const plugins = [];
1103
890
  for (const plugin of this.matterbridge.plugins.array()) {
1104
891
  plugins.push({
@@ -1126,27 +913,18 @@ export class Frontend extends EventEmitter {
1126
913
  schemaJson: plugin.schemaJson,
1127
914
  hasWhiteList: plugin.configJson?.whiteList !== undefined,
1128
915
  hasBlackList: plugin.configJson?.blackList !== undefined,
1129
- // Childbridge mode specific data
1130
916
  matter: plugin.serverNode ? this.matterbridge.getServerNodeData(plugin.serverNode) : undefined,
1131
917
  });
1132
918
  }
1133
919
  return plugins;
1134
920
  }
1135
- /**
1136
- * Retrieves the devices from Matterbridge.
1137
- *
1138
- * @param {string} [pluginName] - The name of the plugin to filter devices by.
1139
- * @returns {ApiDevice[]} An array of ApiDevices for the frontend.
1140
- */
1141
921
  getDevices(pluginName) {
1142
922
  if (this.matterbridge.hasCleanupStarted)
1143
- return []; // Skip if cleanup has started
923
+ return [];
1144
924
  const devices = [];
1145
925
  for (const device of this.matterbridge.devices.array()) {
1146
- // Filter by pluginName if provided
1147
926
  if (pluginName && pluginName !== device.plugin)
1148
927
  continue;
1149
- // Check if the device has the required properties
1150
928
  if (!device.plugin || !device.deviceType || !device.name || !device.deviceName || !device.serialNumber || !device.uniqueId || !device.lifecycle.isReady)
1151
929
  continue;
1152
930
  devices.push({
@@ -1166,39 +944,24 @@ export class Frontend extends EventEmitter {
1166
944
  }
1167
945
  return devices;
1168
946
  }
1169
- /**
1170
- * Retrieves the clusters from a given plugin and endpoint number.
1171
- *
1172
- * Response for /api/clusters
1173
- *
1174
- * @param {string} pluginName - The name of the plugin.
1175
- * @param {number} endpointNumber - The endpoint number.
1176
- * @returns {ApiClusters | undefined} A promise that resolves to the clusters or undefined if not found.
1177
- */
1178
947
  getClusters(pluginName, endpointNumber) {
1179
948
  if (this.matterbridge.hasCleanupStarted)
1180
- return; // Skip if cleanup has started
949
+ return;
1181
950
  const endpoint = this.matterbridge.devices.array().find((d) => d.plugin === pluginName && d.maybeNumber === endpointNumber);
1182
951
  if (!endpoint || !endpoint.plugin || !endpoint.maybeNumber || !endpoint.maybeId || !endpoint.deviceName || !endpoint.serialNumber) {
1183
952
  this.log.error(`getClusters: no device found for plugin ${pluginName} and endpoint number ${endpointNumber}`);
1184
953
  return;
1185
954
  }
1186
- // this.log.debug(`***getClusters: getting clusters for device ${endpoint.deviceName} plugin ${pluginName} endpoint number ${endpointNumber}`);
1187
- // Get the device types from the main endpoint
1188
955
  const deviceTypes = [];
1189
956
  const clusters = [];
1190
957
  endpoint.state.descriptor.deviceTypeList.forEach((d) => {
1191
958
  deviceTypes.push(d.deviceType);
1192
959
  });
1193
- // Get the clusters from the main endpoint
1194
960
  endpoint.forEachAttribute((clusterName, clusterId, attributeName, attributeId, attributeValue) => {
1195
961
  if (typeof attributeValue === 'undefined' || attributeValue === undefined)
1196
962
  return;
1197
963
  if (clusterName === 'EveHistory' && ['configDataGet', 'configDataSet', 'historyStatus', 'historyEntries', 'historyRequest', 'historySetTime', 'rLoc'].includes(attributeName))
1198
964
  return;
1199
- // console.log(
1200
- // `${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}`,
1201
- // );
1202
965
  clusters.push({
1203
966
  endpoint: endpoint.number.toString(),
1204
967
  number: endpoint.number,
@@ -1212,19 +975,12 @@ export class Frontend extends EventEmitter {
1212
975
  attributeLocalValue: attributeValue,
1213
976
  });
1214
977
  });
1215
- // Get the child endpoints
1216
978
  const childEndpoints = endpoint.getChildEndpoints();
1217
- // if (childEndpoints.length === 0) {
1218
- // this.log.debug(`***getClusters: found ${childEndpoints.length} child endpoints for device ${endpoint.deviceName} plugin ${pluginName} and endpoint number ${endpointNumber}`);
1219
- // }
1220
979
  childEndpoints.forEach((childEndpoint) => {
1221
- // istanbul ignore if cause is not reachable: should never happen but ...
1222
980
  if (!childEndpoint.maybeId || !childEndpoint.maybeNumber) {
1223
981
  this.log.error(`getClusters: no child endpoint found for plugin ${pluginName} and endpoint number ${endpointNumber}`);
1224
982
  return;
1225
983
  }
1226
- // this.log.debug(`***getClusters: getting clusters for child endpoint ${childEndpoint.id} of device ${endpoint.deviceName} plugin ${pluginName} endpoint number ${childEndpoint.number}`);
1227
- // Get the device types of the child endpoint
1228
984
  const deviceTypes = [];
1229
985
  childEndpoint.state.descriptor.deviceTypeList.forEach((d) => {
1230
986
  deviceTypes.push(d.deviceType);
@@ -1234,9 +990,6 @@ export class Frontend extends EventEmitter {
1234
990
  return;
1235
991
  if (clusterName === 'EveHistory' && ['configDataGet', 'configDataSet', 'historyStatus', 'historyEntries', 'historyRequest', 'historySetTime', 'rLoc'].includes(attributeName))
1236
992
  return;
1237
- // console.log(
1238
- // `${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}`,
1239
- // );
1240
993
  clusters.push({
1241
994
  endpoint: childEndpoint.number.toString(),
1242
995
  number: childEndpoint.number,
@@ -1256,7 +1009,6 @@ export class Frontend extends EventEmitter {
1256
1009
  async generateDiagnostic() {
1257
1010
  this.log.debug('Generating diagnostic...');
1258
1011
  const serverNodes = [];
1259
- // istanbul ignore else
1260
1012
  if (this.matterbridge.bridgeMode === 'bridge') {
1261
1013
  if (this.matterbridge.serverNode)
1262
1014
  serverNodes.push(this.matterbridge.serverNode);
@@ -1267,7 +1019,6 @@ export class Frontend extends EventEmitter {
1267
1019
  serverNodes.push(plugin.serverNode);
1268
1020
  }
1269
1021
  }
1270
- // istanbul ignore next
1271
1022
  for (const device of this.matterbridge.devices.array()) {
1272
1023
  if (device.serverNode)
1273
1024
  serverNodes.push(device.serverNode);
@@ -1291,15 +1042,8 @@ export class Frontend extends EventEmitter {
1291
1042
  values: [...serverNodes],
1292
1043
  })));
1293
1044
  delete Logger.destinations.diagnostic;
1294
- await wait(500); // Wait for the log to be written
1045
+ await wait(500);
1295
1046
  }
1296
- /**
1297
- * Handles incoming websocket api request messages from the Matterbridge frontend.
1298
- *
1299
- * @param {WebSocket} client - The websocket client that sent the message.
1300
- * @param {WebSocket.RawData} message - The raw data of the message received from the client.
1301
- * @returns {Promise<void>} A promise that resolves when the message has been handled.
1302
- */
1303
1047
  async wsMessageHandler(client, message) {
1304
1048
  let data;
1305
1049
  const sendResponse = (data) => {
@@ -1319,7 +1063,7 @@ export class Frontend extends EventEmitter {
1319
1063
  };
1320
1064
  try {
1321
1065
  data = JSON.parse(message.toString());
1322
- if (!isValidNumber(data.id) || !isValidString(data.dst) || !isValidString(data.src) || !isValidString(data.method) /* || !isValidObject(data.params)*/ || data.dst !== 'Matterbridge') {
1066
+ if (!isValidNumber(data.id) || !isValidString(data.dst) || !isValidString(data.src) || !isValidString(data.method) || data.dst !== 'Matterbridge') {
1323
1067
  this.log.error(`Invalid message from websocket client: ${debugStringify(data)}`);
1324
1068
  sendResponse({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, error: 'Invalid message' });
1325
1069
  return;
@@ -1393,7 +1137,6 @@ export class Frontend extends EventEmitter {
1393
1137
  return;
1394
1138
  })
1395
1139
  .catch((_error) => {
1396
- //
1397
1140
  });
1398
1141
  }
1399
1142
  else {
@@ -1441,7 +1184,6 @@ export class Frontend extends EventEmitter {
1441
1184
  return;
1442
1185
  })
1443
1186
  .catch((_error) => {
1444
- //
1445
1187
  });
1446
1188
  }
1447
1189
  sendResponse({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, success: true });
@@ -1467,7 +1209,6 @@ export class Frontend extends EventEmitter {
1467
1209
  const plugin = this.matterbridge.plugins.get(data.params.pluginName);
1468
1210
  await this.matterbridge.plugins.shutdown(plugin, 'The plugin is restarting.', false, true);
1469
1211
  if (plugin.serverNode) {
1470
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1471
1212
  await this.matterbridge.stopServerNode(plugin.serverNode);
1472
1213
  plugin.serverNode = undefined;
1473
1214
  }
@@ -1477,20 +1218,18 @@ export class Frontend extends EventEmitter {
1477
1218
  this.matterbridge.devices.remove(device);
1478
1219
  }
1479
1220
  }
1480
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1481
1221
  if (plugin.type === 'DynamicPlatform' && !plugin.locked)
1482
1222
  await this.matterbridge.createDynamicPlugin(plugin);
1483
1223
  await this.matterbridge.plugins.load(plugin, true, 'The plugin has been restarted', true);
1484
- plugin.restartRequired = false; // Reset plugin restartRequired
1224
+ plugin.restartRequired = false;
1485
1225
  let needRestart = 0;
1486
1226
  for (const plugin of this.matterbridge.plugins) {
1487
1227
  if (plugin.restartRequired)
1488
1228
  needRestart++;
1489
1229
  }
1490
1230
  if (needRestart === 0) {
1491
- this.wssSendRestartNotRequired(true); // Reset global restart required message
1231
+ this.wssSendRestartNotRequired(true);
1492
1232
  }
1493
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1494
1233
  if (plugin.serverNode)
1495
1234
  await this.matterbridge.startServerNode(plugin.serverNode);
1496
1235
  this.wssSendSnackbarMessage(`Restarted plugin ${data.params.pluginName}`, 5, 'success');
@@ -1755,22 +1494,22 @@ export class Frontend extends EventEmitter {
1755
1494
  if (isValidString(data.params.value, 4)) {
1756
1495
  this.log.debug('Matterbridge logger level:', data.params.value);
1757
1496
  if (data.params.value === 'Debug') {
1758
- await this.matterbridge.setLogLevel("debug" /* LogLevel.DEBUG */);
1497
+ await this.matterbridge.setLogLevel("debug");
1759
1498
  }
1760
1499
  else if (data.params.value === 'Info') {
1761
- await this.matterbridge.setLogLevel("info" /* LogLevel.INFO */);
1500
+ await this.matterbridge.setLogLevel("info");
1762
1501
  }
1763
1502
  else if (data.params.value === 'Notice') {
1764
- await this.matterbridge.setLogLevel("notice" /* LogLevel.NOTICE */);
1503
+ await this.matterbridge.setLogLevel("notice");
1765
1504
  }
1766
1505
  else if (data.params.value === 'Warn') {
1767
- await this.matterbridge.setLogLevel("warn" /* LogLevel.WARN */);
1506
+ await this.matterbridge.setLogLevel("warn");
1768
1507
  }
1769
1508
  else if (data.params.value === 'Error') {
1770
- await this.matterbridge.setLogLevel("error" /* LogLevel.ERROR */);
1509
+ await this.matterbridge.setLogLevel("error");
1771
1510
  }
1772
1511
  else if (data.params.value === 'Fatal') {
1773
- await this.matterbridge.setLogLevel("fatal" /* LogLevel.FATAL */);
1512
+ await this.matterbridge.setLogLevel("fatal");
1774
1513
  }
1775
1514
  await this.matterbridge.nodeContext?.set('matterbridgeLogLevel', this.log.logLevel);
1776
1515
  sendResponse({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, success: true });
@@ -1781,7 +1520,6 @@ export class Frontend extends EventEmitter {
1781
1520
  this.log.debug('Matterbridge file log:', data.params.value);
1782
1521
  this.matterbridge.fileLogger = data.params.value;
1783
1522
  await this.matterbridge.nodeContext?.set('matterbridgeFileLog', data.params.value);
1784
- // Create the file logger for matterbridge
1785
1523
  if (data.params.value)
1786
1524
  AnsiLogger.setGlobalLogfile(path.join(this.matterbridge.matterbridgeDirectory, MATTERBRIDGE_LOGGER_FILE), await this.matterbridge.getLogLevel(), true);
1787
1525
  else
@@ -1810,12 +1548,11 @@ export class Frontend extends EventEmitter {
1810
1548
  else if (data.params.value === 'Fatal') {
1811
1549
  Logger.level = MatterLogLevel.FATAL;
1812
1550
  }
1813
- // Set the global logger callback for the WebSocketServer to the common minimum logLevel
1814
- let callbackLogLevel = "notice" /* LogLevel.NOTICE */;
1815
- if (this.matterbridge.getLogLevel() === "info" /* LogLevel.INFO */ || Logger.level === MatterLogLevel.INFO)
1816
- callbackLogLevel = "info" /* LogLevel.INFO */;
1817
- if (this.matterbridge.getLogLevel() === "debug" /* LogLevel.DEBUG */ || Logger.level === MatterLogLevel.DEBUG)
1818
- callbackLogLevel = "debug" /* LogLevel.DEBUG */;
1551
+ let callbackLogLevel = "notice";
1552
+ if (this.matterbridge.getLogLevel() === "info" || Logger.level === MatterLogLevel.INFO)
1553
+ callbackLogLevel = "info";
1554
+ if (this.matterbridge.getLogLevel() === "debug" || Logger.level === MatterLogLevel.DEBUG)
1555
+ callbackLogLevel = "debug";
1819
1556
  AnsiLogger.setGlobalCallbackLevel(callbackLogLevel);
1820
1557
  this.log.debug(`WebSocketServer logger global callback set to ${callbackLogLevel}`);
1821
1558
  await this.matterbridge.nodeContext?.set('matterLogLevel', Logger.level);
@@ -1867,7 +1604,6 @@ export class Frontend extends EventEmitter {
1867
1604
  }
1868
1605
  break;
1869
1606
  case 'setmatterport':
1870
- // eslint-disable-next-line no-case-declarations
1871
1607
  const port = isValidString(data.params.value) ? parseInt(data.params.value) : 0;
1872
1608
  if (isValidNumber(port, 5540, 5600)) {
1873
1609
  this.log.debug(`Set matter commissioning port to ${CYAN}${port}${db}`);
@@ -1887,7 +1623,6 @@ export class Frontend extends EventEmitter {
1887
1623
  }
1888
1624
  break;
1889
1625
  case 'setmatterdiscriminator':
1890
- // eslint-disable-next-line no-case-declarations
1891
1626
  const discriminator = isValidString(data.params.value) ? parseInt(data.params.value) : 0;
1892
1627
  if (isValidNumber(discriminator, 0, 4095)) {
1893
1628
  this.log.debug(`Set matter commissioning discriminator to ${CYAN}${discriminator}${db}`);
@@ -1907,7 +1642,6 @@ export class Frontend extends EventEmitter {
1907
1642
  }
1908
1643
  break;
1909
1644
  case 'setmatterpasscode':
1910
- // eslint-disable-next-line no-case-declarations
1911
1645
  const passcode = isValidString(data.params.value) ? parseInt(data.params.value) : 0;
1912
1646
  if (isValidNumber(passcode, 1, 99999998) && CommissioningOptions.FORBIDDEN_PASSCODES.includes(passcode) === false) {
1913
1647
  this.matterbridge.passcode = passcode;
@@ -1953,19 +1687,15 @@ export class Frontend extends EventEmitter {
1953
1687
  return;
1954
1688
  }
1955
1689
  const config = plugin.configJson;
1956
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1957
1690
  const select = plugin.schemaJson?.properties?.blackList?.selectFrom;
1958
- // this.log.debug(`SelectDevice(selectMode ${select}) data ${debugStringify(data)}`);
1959
1691
  if (select === 'serial')
1960
1692
  this.log.info(`Selected device serial ${data.params.serial}`);
1961
1693
  if (select === 'name')
1962
1694
  this.log.info(`Selected device name ${data.params.name}`);
1963
1695
  if (config && select && (select === 'serial' || select === 'name')) {
1964
- // Remove postfix from the serial if it exists
1965
1696
  if (config.postfix) {
1966
1697
  data.params.serial = data.params.serial.replace('-' + config.postfix, '');
1967
1698
  }
1968
- // Add the serial to the whiteList if the whiteList exists and the serial or name is not already in it
1969
1699
  if (isValidArray(config.whiteList, 1)) {
1970
1700
  if (select === 'serial' && !config.whiteList.includes(data.params.serial)) {
1971
1701
  config.whiteList.push(data.params.serial);
@@ -1974,7 +1704,6 @@ export class Frontend extends EventEmitter {
1974
1704
  config.whiteList.push(data.params.name);
1975
1705
  }
1976
1706
  }
1977
- // Remove the serial from the blackList if the blackList exists and the serial or name is in it
1978
1707
  if (isValidArray(config.blackList, 1)) {
1979
1708
  if (select === 'serial' && config.blackList.includes(data.params.serial)) {
1980
1709
  config.blackList = config.blackList.filter((item) => item !== localData.params.serial);
@@ -2002,9 +1731,7 @@ export class Frontend extends EventEmitter {
2002
1731
  return;
2003
1732
  }
2004
1733
  const config = plugin.configJson;
2005
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
2006
1734
  const select = plugin.schemaJson?.properties?.blackList?.selectFrom;
2007
- // this.log.debug(`UnselectDevice(selectMode ${select}) data ${debugStringify(data)}`);
2008
1735
  if (select === 'serial')
2009
1736
  this.log.info(`Unselected device serial ${data.params.serial}`);
2010
1737
  if (select === 'name')
@@ -2013,7 +1740,6 @@ export class Frontend extends EventEmitter {
2013
1740
  if (config.postfix) {
2014
1741
  data.params.serial = data.params.serial.replace('-' + config.postfix, '');
2015
1742
  }
2016
- // Remove the serial from the whiteList if the whiteList exists and the serial is in it
2017
1743
  if (isValidArray(config.whiteList, 1)) {
2018
1744
  if (select === 'serial' && config.whiteList.includes(data.params.serial)) {
2019
1745
  config.whiteList = config.whiteList.filter((item) => item !== localData.params.serial);
@@ -2022,7 +1748,6 @@ export class Frontend extends EventEmitter {
2022
1748
  config.whiteList = config.whiteList.filter((item) => item !== localData.params.name);
2023
1749
  }
2024
1750
  }
2025
- // Add the serial to the blackList
2026
1751
  if (isValidArray(config.blackList)) {
2027
1752
  if (select === 'serial' && !config.blackList.includes(data.params.serial)) {
2028
1753
  config.blackList.push(data.params.serial);
@@ -2045,7 +1770,6 @@ export class Frontend extends EventEmitter {
2045
1770
  }
2046
1771
  }
2047
1772
  else {
2048
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
2049
1773
  const localData = data;
2050
1774
  this.log.error(`Invalid method from websocket client: ${debugStringify(localData)}`);
2051
1775
  sendResponse({ id: localData.id, method: localData.method, src: 'Matterbridge', dst: localData.src, error: 'Invalid method' });
@@ -2055,46 +1779,23 @@ export class Frontend extends EventEmitter {
2055
1779
  inspectError(this.log, `Error processing message "${message}" from websocket client`, error);
2056
1780
  }
2057
1781
  }
2058
- /**
2059
- * Sends a WebSocket log message to all connected clients. The function is called by AnsiLogger.setGlobalCallback.
2060
- *
2061
- * @param {string} level - The logger level of the message: debug info notice warn error fatal...
2062
- * @param {string} time - The time string of the message
2063
- * @param {string} name - The logger name of the message
2064
- * @param {string} message - The content of the message.
2065
- *
2066
- * @remarks
2067
- * The function removes ANSI escape codes, leading asterisks, non-printable characters, and replaces all occurrences of \t and \n.
2068
- * It also replaces all occurrences of \" with " and angle-brackets with &lt; and &gt;.
2069
- * The function sends the message to all connected clients.
2070
- */
2071
1782
  wssSendLogMessage(level, time, name, message) {
2072
1783
  if (!this.listening || this.webSocketServer?.clients.size === 0)
2073
1784
  return;
2074
1785
  if (!level || !time || !name || !message)
2075
1786
  return;
2076
- // Remove ANSI escape codes from the message
2077
- // eslint-disable-next-line no-control-regex
2078
1787
  message = message.replace(/\x1B\[[0-9;]*[m|s|u|K]/g, '');
2079
- // Remove leading asterisks from the message
2080
1788
  message = message.replace(/^\*+/, '');
2081
- // Replace all occurrences of \t and \n
2082
1789
  message = message.replace(/[\t\n]/g, '');
2083
- // Remove non-printable characters
2084
- // eslint-disable-next-line no-control-regex
2085
1790
  message = message.replace(/[\x00-\x1F\x7F]/g, '');
2086
- // Replace all occurrences of \" with "
2087
1791
  message = message.replace(/\\"/g, '"');
2088
- // Define the maximum allowed length for continuous characters without a space
2089
1792
  const maxContinuousLength = 100;
2090
1793
  const keepStartLength = 20;
2091
1794
  const keepEndLength = 20;
2092
- // Split the message into words
2093
1795
  if (level !== 'spawn') {
2094
1796
  message = message
2095
1797
  .split(' ')
2096
1798
  .map((word) => {
2097
- // If the word length exceeds the max continuous length, insert spaces and truncate
2098
1799
  if (word.length > maxContinuousLength) {
2099
1800
  return word.slice(0, keepStartLength) + ' ... ' + word.slice(-keepEndLength);
2100
1801
  }
@@ -2102,34 +1803,14 @@ export class Frontend extends EventEmitter {
2102
1803
  })
2103
1804
  .join(' ');
2104
1805
  }
2105
- // Send the message to all connected clients
2106
1806
  this.wssBroadcastMessage({ id: 0, src: 'Matterbridge', dst: 'Frontend', method: 'log', success: true, response: { level, time, name, message } });
2107
1807
  }
2108
- /**
2109
- * Sends a need to refresh WebSocket message to all connected clients.
2110
- *
2111
- * @param {string} changed - The changed value.
2112
- * @param {Record<string, unknown>} params - Additional parameters to send with the message.
2113
- * possible values for changed:
2114
- * - 'settings' (when the bridge has started in bridge mode or childbridge mode and when update finds a new version)
2115
- * - 'plugins'
2116
- * - 'devices'
2117
- * - 'matter' with param 'matter' (QRDiv component)
2118
- * @param {ApiMatter} params.matter - The matter device that has changed. Required if changed is 'matter'.
2119
- */
2120
1808
  wssSendRefreshRequired(changed, params) {
2121
1809
  if (!this.listening || this.webSocketServer?.clients.size === 0)
2122
1810
  return;
2123
1811
  this.log.debug('Sending a refresh required message to all connected clients');
2124
- // Send the message to all connected clients
2125
1812
  this.wssBroadcastMessage({ id: 0, src: 'Matterbridge', dst: 'Frontend', method: 'refresh_required', success: true, response: { changed, ...params } });
2126
1813
  }
2127
- /**
2128
- * Sends a need to restart WebSocket message to all connected clients.
2129
- *
2130
- * @param {boolean} snackbar - If true, a snackbar message will be sent to all connected clients. Default is true.
2131
- * @param {boolean} fixed - If true, the restart is fixed and will not be reset by plugin restarts. Default is false.
2132
- */
2133
1814
  wssSendRestartRequired(snackbar = true, fixed = false) {
2134
1815
  if (!this.listening || this.webSocketServer?.clients.size === 0)
2135
1816
  return;
@@ -2138,14 +1819,8 @@ export class Frontend extends EventEmitter {
2138
1819
  this.matterbridge.fixedRestartRequired = fixed;
2139
1820
  if (snackbar === true)
2140
1821
  this.wssSendSnackbarMessage(`Restart required`, 0);
2141
- // Send the message to all connected clients
2142
1822
  this.wssBroadcastMessage({ id: 0, src: 'Matterbridge', dst: 'Frontend', method: 'restart_required', success: true, response: { fixed } });
2143
1823
  }
2144
- /**
2145
- * Sends a no need to restart WebSocket message to all connected clients.
2146
- *
2147
- * @param {boolean} snackbar - If true, the snackbar message will be cleared from all connected clients. Default is true.
2148
- */
2149
1824
  wssSendRestartNotRequired(snackbar = true) {
2150
1825
  if (!this.listening || this.webSocketServer?.clients.size === 0)
2151
1826
  return;
@@ -2153,133 +1828,57 @@ export class Frontend extends EventEmitter {
2153
1828
  this.matterbridge.restartRequired = false;
2154
1829
  if (snackbar === true)
2155
1830
  this.wssSendCloseSnackbarMessage(`Restart required`);
2156
- // Send the message to all connected clients
2157
1831
  this.wssBroadcastMessage({ id: 0, src: 'Matterbridge', dst: 'Frontend', method: 'restart_not_required', success: true });
2158
1832
  }
2159
- /**
2160
- * Sends a need to update WebSocket message to all connected clients.
2161
- *
2162
- * @param {boolean} devVersion - If true, the update is for a development version. Default is false.
2163
- */
2164
1833
  wssSendUpdateRequired(devVersion = false) {
2165
1834
  if (!this.listening || this.webSocketServer?.clients.size === 0)
2166
1835
  return;
2167
1836
  this.log.debug('Sending an update required message to all connected clients');
2168
1837
  this.matterbridge.updateRequired = true;
2169
- // Send the message to all connected clients
2170
1838
  this.wssBroadcastMessage({ id: 0, src: 'Matterbridge', dst: 'Frontend', method: 'update_required', success: true, response: { devVersion } });
2171
1839
  }
2172
- /**
2173
- * Sends a cpu update message to all connected clients.
2174
- *
2175
- * @param {number} cpuUsage - The CPU usage percentage to send.
2176
- * @param {number} processCpuUsage - The CPU usage percentage of the process to send.
2177
- */
2178
1840
  wssSendCpuUpdate(cpuUsage, processCpuUsage) {
2179
1841
  if (!this.listening || this.webSocketServer?.clients.size === 0)
2180
1842
  return;
2181
1843
  if (hasParameter('debug'))
2182
1844
  this.log.debug('Sending a cpu update message to all connected clients');
2183
- // Send the message to all connected clients
2184
1845
  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 } });
2185
1846
  }
2186
- /**
2187
- * Sends a memory update message to all connected clients.
2188
- *
2189
- * @param {string} totalMemory - The total memory in bytes.
2190
- * @param {string} freeMemory - The free memory in bytes.
2191
- * @param {string} rss - The resident set size in bytes.
2192
- * @param {string} heapTotal - The total heap memory in bytes.
2193
- * @param {string} heapUsed - The used heap memory in bytes.
2194
- * @param {string} external - The external memory in bytes.
2195
- * @param {string} arrayBuffers - The array buffers memory in bytes.
2196
- */
2197
1847
  wssSendMemoryUpdate(totalMemory, freeMemory, rss, heapTotal, heapUsed, external, arrayBuffers) {
2198
1848
  if (!this.listening || this.webSocketServer?.clients.size === 0)
2199
1849
  return;
2200
1850
  if (hasParameter('debug'))
2201
1851
  this.log.debug('Sending a memory update message to all connected clients');
2202
- // Send the message to all connected clients
2203
1852
  this.wssBroadcastMessage({ id: 0, src: 'Matterbridge', dst: 'Frontend', method: 'memory_update', success: true, response: { totalMemory, freeMemory, rss, heapTotal, heapUsed, external, arrayBuffers } });
2204
1853
  }
2205
- /**
2206
- * Sends an uptime update message to all connected clients.
2207
- *
2208
- * @param {string} systemUptime - The system uptime in a human-readable format.
2209
- * @param {string} processUptime - The process uptime in a human-readable format.
2210
- */
2211
1854
  wssSendUptimeUpdate(systemUptime, processUptime) {
2212
1855
  if (!this.listening || this.webSocketServer?.clients.size === 0)
2213
1856
  return;
2214
1857
  if (hasParameter('debug'))
2215
1858
  this.log.debug('Sending a uptime update message to all connected clients');
2216
- // Send the message to all connected clients
2217
1859
  this.wssBroadcastMessage({ id: 0, src: 'Matterbridge', dst: 'Frontend', method: 'uptime_update', success: true, response: { systemUptime, processUptime } });
2218
1860
  }
2219
- /**
2220
- * Sends an open snackbar message to all connected clients.
2221
- *
2222
- * @param {string} message - The message to send.
2223
- * @param {number} timeout - The timeout in seconds for the snackbar message. Default is 5 seconds.
2224
- * @param {'info' | 'warning' | 'error' | 'success'} severity - The severity of the message.
2225
- * possible values are: 'info', 'warning', 'error', 'success'. Default is 'info'.
2226
- *
2227
- * @remarks
2228
- * If timeout is 0, the snackbar message will be displayed until closed by the user.
2229
- */
2230
1861
  wssSendSnackbarMessage(message, timeout = 5, severity = 'info') {
2231
1862
  if (!this.listening || this.webSocketServer?.clients.size === 0)
2232
1863
  return;
2233
1864
  this.log.debug('Sending a snackbar message to all connected clients');
2234
- // Send the message to all connected clients
2235
1865
  this.wssBroadcastMessage({ id: 0, src: 'Matterbridge', dst: 'Frontend', method: 'snackbar', success: true, response: { message, timeout, severity } });
2236
1866
  }
2237
- /**
2238
- * Sends a close snackbar message to all connected clients.
2239
- * It will close the snackbar message with the same message and timeout = 0.
2240
- *
2241
- * @param {string} message - The message to send.
2242
- */
2243
1867
  wssSendCloseSnackbarMessage(message) {
2244
1868
  if (!this.listening || this.webSocketServer?.clients.size === 0)
2245
1869
  return;
2246
1870
  this.log.debug('Sending a close snackbar message to all connected clients');
2247
- // Send the message to all connected clients
2248
1871
  this.wssBroadcastMessage({ id: 0, src: 'Matterbridge', dst: 'Frontend', method: 'close_snackbar', success: true, response: { message } });
2249
1872
  }
2250
- /**
2251
- * Sends an attribute update message to all connected WebSocket clients.
2252
- *
2253
- * @param {string | undefined} plugin - The name of the plugin.
2254
- * @param {string | undefined} serialNumber - The serial number of the device.
2255
- * @param {string | undefined} uniqueId - The unique identifier of the device.
2256
- * @param {EndpointNumber} number - The endpoint number where the attribute belongs.
2257
- * @param {string} id - The endpoint id where the attribute belongs.
2258
- * @param {string} cluster - The cluster name where the attribute belongs.
2259
- * @param {string} attribute - The name of the attribute that changed.
2260
- * @param {number | string | boolean} value - The new value of the attribute.
2261
- *
2262
- * @remarks
2263
- * This method logs a debug message and sends a JSON-formatted message to all connected WebSocket clients
2264
- * with the updated attribute information.
2265
- */
2266
1873
  wssSendAttributeChangedMessage(plugin, serialNumber, uniqueId, number, id, cluster, attribute, value) {
2267
1874
  if (!this.listening || this.webSocketServer?.clients.size === 0)
2268
1875
  return;
2269
1876
  this.log.debug('Sending an attribute update message to all connected clients');
2270
- // Send the message to all connected clients
2271
1877
  this.wssBroadcastMessage({ id: 0, src: 'Matterbridge', dst: 'Frontend', method: 'state_update', success: true, response: { plugin, serialNumber, uniqueId, number, id, cluster, attribute, value } });
2272
1878
  }
2273
- /**
2274
- * Sends a message to all connected clients.
2275
- * This is an helper function to send a broadcast message to all connected clients.
2276
- *
2277
- * @param {WsMessageBroadcast} msg - The message to send.
2278
- */
2279
1879
  wssBroadcastMessage(msg) {
2280
1880
  if (!this.listening || this.webSocketServer?.clients.size === 0)
2281
1881
  return;
2282
- // Send the message to all connected clients
2283
1882
  const stringifiedMsg = JSON.stringify(msg);
2284
1883
  if (msg.method !== 'log')
2285
1884
  this.log.debug(`Sending a broadcast message: ${debugStringify(msg)}`);
@@ -2290,4 +1889,3 @@ export class Frontend extends EventEmitter {
2290
1889
  });
2291
1890
  }
2292
1891
  }
2293
- //# sourceMappingURL=frontend.js.map