matterbridge 3.3.3 → 3.3.4-dev-20251020-4d2dd49
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.
- package/CHANGELOG.md +21 -0
- package/dist/broadcastServer.js +1 -86
- package/dist/broadcastServerTypes.js +0 -24
- package/dist/cli.js +110 -444
- package/dist/cliEmitter.js +0 -37
- package/dist/cliHistory.js +15 -95
- package/dist/clusters/export.js +0 -2
- package/dist/defaultConfigSchema.js +0 -24
- package/dist/deviceManager.js +1 -124
- package/dist/devices/airConditioner.js +0 -57
- package/dist/devices/batteryStorage.js +1 -48
- package/dist/devices/cooktop.js +0 -55
- package/dist/devices/dishwasher.js +0 -57
- package/dist/devices/evse.js +10 -74
- package/dist/devices/export.js +0 -5
- package/dist/devices/extractorHood.js +0 -42
- package/dist/devices/heatPump.js +2 -50
- package/dist/devices/laundryDryer.js +3 -62
- package/dist/devices/laundryWasher.js +4 -70
- package/dist/devices/microwaveOven.js +5 -88
- package/dist/devices/oven.js +0 -85
- package/dist/devices/refrigerator.js +0 -102
- package/dist/devices/roboticVacuumCleaner.js +9 -100
- package/dist/devices/solarPower.js +0 -38
- package/dist/devices/speaker.js +0 -84
- package/dist/devices/temperatureControl.js +3 -25
- package/dist/devices/waterHeater.js +2 -82
- package/dist/dgram/coap.js +13 -126
- package/dist/dgram/dgram.js +2 -114
- package/dist/dgram/mb_coap.js +3 -41
- package/dist/dgram/mb_mdns.js +15 -80
- package/dist/dgram/mdns.js +137 -299
- package/dist/dgram/multicast.js +1 -62
- package/dist/dgram/unicast.js +0 -54
- package/dist/frontend.js +34 -413
- package/dist/frontendTypes.js +0 -45
- package/dist/helpers.js +0 -53
- package/dist/index.js +0 -25
- package/dist/logger/export.js +0 -1
- package/dist/matter/behaviors.js +0 -2
- package/dist/matter/clusters.js +0 -2
- package/dist/matter/devices.js +0 -2
- package/dist/matter/endpoints.js +0 -2
- package/dist/matter/export.js +0 -3
- package/dist/matter/types.js +0 -3
- package/dist/matterbridge.js +51 -873
- package/dist/matterbridgeAccessoryPlatform.js +0 -36
- package/dist/matterbridgeBehaviors.js +5 -71
- package/dist/matterbridgeDeviceTypes.js +17 -630
- package/dist/matterbridgeDynamicPlatform.js +0 -36
- package/dist/matterbridgeEndpoint.js +58 -1412
- package/dist/matterbridgeEndpointHelpers.js +10 -368
- package/dist/matterbridgePlatform.js +1 -341
- package/dist/matterbridgeTypes.js +0 -26
- package/dist/pluginManager.js +3 -325
- package/dist/shelly.js +7 -168
- package/dist/storage/export.js +0 -1
- package/dist/update.js +0 -69
- package/dist/utils/colorUtils.js +2 -97
- package/dist/utils/commandLine.js +6 -55
- package/dist/utils/copyDirectory.js +1 -38
- package/dist/utils/createDirectory.js +0 -33
- package/dist/utils/createZip.js +2 -47
- package/dist/utils/deepCopy.js +0 -39
- package/dist/utils/deepEqual.js +1 -72
- package/dist/utils/error.js +0 -41
- package/dist/utils/export.js +0 -1
- package/dist/utils/hex.js +0 -124
- package/dist/utils/inspector.js +200 -0
- package/dist/utils/isvalid.js +0 -101
- package/dist/utils/jestHelpers.js +3 -153
- package/dist/utils/network.js +5 -108
- package/dist/utils/spawn.js +0 -71
- package/dist/utils/tracker.js +229 -0
- package/dist/utils/wait.js +8 -60
- package/frontend/build/assets/index.js +4 -4
- package/frontend/build/assets/vendor_mdi.js +1 -1
- package/frontend/package.json +1 -1
- package/npm-shrinkwrap.json +44 -44
- package/package.json +2 -3
- package/dist/broadcastServer.d.ts +0 -105
- package/dist/broadcastServer.d.ts.map +0 -1
- package/dist/broadcastServer.js.map +0 -1
- package/dist/broadcastServerTypes.d.ts +0 -719
- package/dist/broadcastServerTypes.d.ts.map +0 -1
- package/dist/broadcastServerTypes.js.map +0 -1
- package/dist/cli.d.ts +0 -26
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/cliEmitter.d.ts +0 -50
- package/dist/cliEmitter.d.ts.map +0 -1
- package/dist/cliEmitter.js.map +0 -1
- package/dist/cliHistory.d.ts +0 -74
- package/dist/cliHistory.d.ts.map +0 -1
- package/dist/cliHistory.js.map +0 -1
- package/dist/clusters/export.d.ts +0 -2
- package/dist/clusters/export.d.ts.map +0 -1
- package/dist/clusters/export.js.map +0 -1
- package/dist/defaultConfigSchema.d.ts +0 -28
- package/dist/defaultConfigSchema.d.ts.map +0 -1
- package/dist/defaultConfigSchema.js.map +0 -1
- package/dist/deviceManager.d.ts +0 -117
- package/dist/deviceManager.d.ts.map +0 -1
- package/dist/deviceManager.js.map +0 -1
- package/dist/devices/airConditioner.d.ts +0 -98
- package/dist/devices/airConditioner.d.ts.map +0 -1
- package/dist/devices/airConditioner.js.map +0 -1
- package/dist/devices/batteryStorage.d.ts +0 -48
- package/dist/devices/batteryStorage.d.ts.map +0 -1
- package/dist/devices/batteryStorage.js.map +0 -1
- package/dist/devices/cooktop.d.ts +0 -60
- package/dist/devices/cooktop.d.ts.map +0 -1
- package/dist/devices/cooktop.js.map +0 -1
- package/dist/devices/dishwasher.d.ts +0 -71
- package/dist/devices/dishwasher.d.ts.map +0 -1
- package/dist/devices/dishwasher.js.map +0 -1
- package/dist/devices/evse.d.ts +0 -75
- package/dist/devices/evse.d.ts.map +0 -1
- package/dist/devices/evse.js.map +0 -1
- package/dist/devices/export.d.ts +0 -17
- package/dist/devices/export.d.ts.map +0 -1
- package/dist/devices/export.js.map +0 -1
- package/dist/devices/extractorHood.d.ts +0 -46
- package/dist/devices/extractorHood.d.ts.map +0 -1
- package/dist/devices/extractorHood.js.map +0 -1
- package/dist/devices/heatPump.d.ts +0 -47
- package/dist/devices/heatPump.d.ts.map +0 -1
- package/dist/devices/heatPump.js.map +0 -1
- package/dist/devices/laundryDryer.d.ts +0 -67
- package/dist/devices/laundryDryer.d.ts.map +0 -1
- package/dist/devices/laundryDryer.js.map +0 -1
- package/dist/devices/laundryWasher.d.ts +0 -81
- package/dist/devices/laundryWasher.d.ts.map +0 -1
- package/dist/devices/laundryWasher.js.map +0 -1
- package/dist/devices/microwaveOven.d.ts +0 -168
- package/dist/devices/microwaveOven.d.ts.map +0 -1
- package/dist/devices/microwaveOven.js.map +0 -1
- package/dist/devices/oven.d.ts +0 -105
- package/dist/devices/oven.d.ts.map +0 -1
- package/dist/devices/oven.js.map +0 -1
- package/dist/devices/refrigerator.d.ts +0 -118
- package/dist/devices/refrigerator.d.ts.map +0 -1
- package/dist/devices/refrigerator.js.map +0 -1
- package/dist/devices/roboticVacuumCleaner.d.ts +0 -112
- package/dist/devices/roboticVacuumCleaner.d.ts.map +0 -1
- package/dist/devices/roboticVacuumCleaner.js.map +0 -1
- package/dist/devices/solarPower.d.ts +0 -40
- package/dist/devices/solarPower.d.ts.map +0 -1
- package/dist/devices/solarPower.js.map +0 -1
- package/dist/devices/speaker.d.ts +0 -87
- package/dist/devices/speaker.d.ts.map +0 -1
- package/dist/devices/speaker.js.map +0 -1
- package/dist/devices/temperatureControl.d.ts +0 -166
- package/dist/devices/temperatureControl.d.ts.map +0 -1
- package/dist/devices/temperatureControl.js.map +0 -1
- package/dist/devices/waterHeater.d.ts +0 -111
- package/dist/devices/waterHeater.d.ts.map +0 -1
- package/dist/devices/waterHeater.js.map +0 -1
- package/dist/dgram/coap.d.ts +0 -205
- package/dist/dgram/coap.d.ts.map +0 -1
- package/dist/dgram/coap.js.map +0 -1
- package/dist/dgram/dgram.d.ts +0 -141
- package/dist/dgram/dgram.d.ts.map +0 -1
- package/dist/dgram/dgram.js.map +0 -1
- package/dist/dgram/mb_coap.d.ts +0 -24
- package/dist/dgram/mb_coap.d.ts.map +0 -1
- package/dist/dgram/mb_coap.js.map +0 -1
- package/dist/dgram/mb_mdns.d.ts +0 -24
- package/dist/dgram/mb_mdns.d.ts.map +0 -1
- package/dist/dgram/mb_mdns.js.map +0 -1
- package/dist/dgram/mdns.d.ts +0 -290
- package/dist/dgram/mdns.d.ts.map +0 -1
- package/dist/dgram/mdns.js.map +0 -1
- package/dist/dgram/multicast.d.ts +0 -67
- package/dist/dgram/multicast.d.ts.map +0 -1
- package/dist/dgram/multicast.js.map +0 -1
- package/dist/dgram/unicast.d.ts +0 -56
- package/dist/dgram/unicast.d.ts.map +0 -1
- package/dist/dgram/unicast.js.map +0 -1
- package/dist/frontend.d.ts +0 -235
- package/dist/frontend.d.ts.map +0 -1
- package/dist/frontend.js.map +0 -1
- package/dist/frontendTypes.d.ts +0 -529
- package/dist/frontendTypes.d.ts.map +0 -1
- package/dist/frontendTypes.js.map +0 -1
- package/dist/helpers.d.ts +0 -48
- package/dist/helpers.d.ts.map +0 -1
- package/dist/helpers.js.map +0 -1
- package/dist/index.d.ts +0 -33
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/logger/export.d.ts +0 -2
- package/dist/logger/export.d.ts.map +0 -1
- package/dist/logger/export.js.map +0 -1
- package/dist/matter/behaviors.d.ts +0 -2
- package/dist/matter/behaviors.d.ts.map +0 -1
- package/dist/matter/behaviors.js.map +0 -1
- package/dist/matter/clusters.d.ts +0 -2
- package/dist/matter/clusters.d.ts.map +0 -1
- package/dist/matter/clusters.js.map +0 -1
- package/dist/matter/devices.d.ts +0 -2
- package/dist/matter/devices.d.ts.map +0 -1
- package/dist/matter/devices.js.map +0 -1
- package/dist/matter/endpoints.d.ts +0 -2
- package/dist/matter/endpoints.d.ts.map +0 -1
- package/dist/matter/endpoints.js.map +0 -1
- package/dist/matter/export.d.ts +0 -5
- package/dist/matter/export.d.ts.map +0 -1
- package/dist/matter/export.js.map +0 -1
- package/dist/matter/types.d.ts +0 -3
- package/dist/matter/types.d.ts.map +0 -1
- package/dist/matter/types.js.map +0 -1
- package/dist/matterbridge.d.ts +0 -469
- package/dist/matterbridge.d.ts.map +0 -1
- package/dist/matterbridge.js.map +0 -1
- package/dist/matterbridgeAccessoryPlatform.d.ts +0 -42
- package/dist/matterbridgeAccessoryPlatform.d.ts.map +0 -1
- package/dist/matterbridgeAccessoryPlatform.js.map +0 -1
- package/dist/matterbridgeBehaviors.d.ts +0 -2399
- package/dist/matterbridgeBehaviors.d.ts.map +0 -1
- package/dist/matterbridgeBehaviors.js.map +0 -1
- package/dist/matterbridgeDeviceTypes.d.ts +0 -761
- package/dist/matterbridgeDeviceTypes.d.ts.map +0 -1
- package/dist/matterbridgeDeviceTypes.js.map +0 -1
- package/dist/matterbridgeDynamicPlatform.d.ts +0 -42
- package/dist/matterbridgeDynamicPlatform.d.ts.map +0 -1
- package/dist/matterbridgeDynamicPlatform.js.map +0 -1
- package/dist/matterbridgeEndpoint.d.ts +0 -1545
- package/dist/matterbridgeEndpoint.d.ts.map +0 -1
- package/dist/matterbridgeEndpoint.js.map +0 -1
- package/dist/matterbridgeEndpointHelpers.d.ts +0 -560
- package/dist/matterbridgeEndpointHelpers.d.ts.map +0 -1
- package/dist/matterbridgeEndpointHelpers.js.map +0 -1
- package/dist/matterbridgePlatform.d.ts +0 -402
- package/dist/matterbridgePlatform.d.ts.map +0 -1
- package/dist/matterbridgePlatform.js.map +0 -1
- package/dist/matterbridgeTypes.d.ts +0 -209
- package/dist/matterbridgeTypes.d.ts.map +0 -1
- package/dist/matterbridgeTypes.js.map +0 -1
- package/dist/pluginManager.d.ts +0 -353
- package/dist/pluginManager.d.ts.map +0 -1
- package/dist/pluginManager.js.map +0 -1
- package/dist/shelly.d.ts +0 -174
- package/dist/shelly.d.ts.map +0 -1
- package/dist/shelly.js.map +0 -1
- package/dist/storage/export.d.ts +0 -2
- package/dist/storage/export.d.ts.map +0 -1
- package/dist/storage/export.js.map +0 -1
- package/dist/update.d.ts +0 -75
- package/dist/update.d.ts.map +0 -1
- package/dist/update.js.map +0 -1
- package/dist/utils/colorUtils.d.ts +0 -99
- package/dist/utils/colorUtils.d.ts.map +0 -1
- package/dist/utils/colorUtils.js.map +0 -1
- package/dist/utils/commandLine.d.ts +0 -59
- package/dist/utils/commandLine.d.ts.map +0 -1
- package/dist/utils/commandLine.js.map +0 -1
- package/dist/utils/copyDirectory.d.ts +0 -33
- package/dist/utils/copyDirectory.d.ts.map +0 -1
- package/dist/utils/copyDirectory.js.map +0 -1
- package/dist/utils/createDirectory.d.ts +0 -34
- package/dist/utils/createDirectory.d.ts.map +0 -1
- package/dist/utils/createDirectory.js.map +0 -1
- package/dist/utils/createZip.d.ts +0 -39
- package/dist/utils/createZip.d.ts.map +0 -1
- package/dist/utils/createZip.js.map +0 -1
- package/dist/utils/deepCopy.d.ts +0 -32
- package/dist/utils/deepCopy.d.ts.map +0 -1
- package/dist/utils/deepCopy.js.map +0 -1
- package/dist/utils/deepEqual.d.ts +0 -54
- package/dist/utils/deepEqual.d.ts.map +0 -1
- package/dist/utils/deepEqual.js.map +0 -1
- package/dist/utils/error.d.ts +0 -44
- package/dist/utils/error.d.ts.map +0 -1
- package/dist/utils/error.js.map +0 -1
- package/dist/utils/export.d.ts +0 -13
- package/dist/utils/export.d.ts.map +0 -1
- package/dist/utils/export.js.map +0 -1
- package/dist/utils/hex.d.ts +0 -89
- package/dist/utils/hex.d.ts.map +0 -1
- package/dist/utils/hex.js.map +0 -1
- package/dist/utils/isvalid.d.ts +0 -103
- package/dist/utils/isvalid.d.ts.map +0 -1
- package/dist/utils/isvalid.js.map +0 -1
- package/dist/utils/jestHelpers.d.ts +0 -137
- package/dist/utils/jestHelpers.d.ts.map +0 -1
- package/dist/utils/jestHelpers.js.map +0 -1
- package/dist/utils/network.d.ts +0 -115
- package/dist/utils/network.d.ts.map +0 -1
- package/dist/utils/network.js.map +0 -1
- package/dist/utils/spawn.d.ts +0 -35
- package/dist/utils/spawn.d.ts.map +0 -1
- package/dist/utils/spawn.js.map +0 -1
- package/dist/utils/wait.d.ts +0 -54
- package/dist/utils/wait.d.ts.map +0 -1
- 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
|
|
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('frontend', this.log);
|
|
65
39
|
this.server.on('broadcast_message', this.msgHandler.bind(this));
|
|
@@ -119,42 +93,13 @@ export class Frontend extends EventEmitter {
|
|
|
119
93
|
async start(port = 8283) {
|
|
120
94
|
this.port = port;
|
|
121
95
|
this.log.debug(`Initializing the frontend ${hasParameter('ssl') ? 'https' : 'http'} server on port ${YELLOW}${this.port}${db}`);
|
|
122
|
-
// Initialize multer with the upload directory
|
|
123
96
|
const multer = await import('multer');
|
|
124
|
-
const uploadDir = path.join(this.matterbridge.matterbridgeDirectory, 'uploads');
|
|
97
|
+
const uploadDir = path.join(this.matterbridge.matterbridgeDirectory, 'uploads');
|
|
125
98
|
const upload = multer.default({ dest: uploadDir });
|
|
126
|
-
// Create the express app that serves the frontend
|
|
127
99
|
const express = await import('express');
|
|
128
100
|
this.expressApp = express.default();
|
|
129
|
-
// Inject logging/debug wrapper for route/middleware registration
|
|
130
|
-
/*
|
|
131
|
-
const methods = ['get', 'post', 'put', 'delete', 'use'];
|
|
132
|
-
for (const method of methods) {
|
|
133
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
134
|
-
const original = (this.expressApp as any)[method].bind(this.expressApp);
|
|
135
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
136
|
-
(this.expressApp as any)[method] = (path: any, ...rest: any) => {
|
|
137
|
-
try {
|
|
138
|
-
console.log(`[DEBUG] Registering ${method.toUpperCase()} route:`, path);
|
|
139
|
-
return original(path, ...rest);
|
|
140
|
-
} catch (err) {
|
|
141
|
-
console.error(`[ERROR] Failed to register route: ${path}`);
|
|
142
|
-
throw err;
|
|
143
|
-
}
|
|
144
|
-
};
|
|
145
|
-
}
|
|
146
|
-
*/
|
|
147
|
-
// Log all requests to the server for debugging
|
|
148
|
-
/*
|
|
149
|
-
this.expressApp.use((req, res, next) => {
|
|
150
|
-
this.log.debug(`***Received request on expressApp: ${req.method} ${req.url}`);
|
|
151
|
-
next();
|
|
152
|
-
});
|
|
153
|
-
*/
|
|
154
|
-
// Serve static files from 'frontend/build' directory
|
|
155
101
|
this.expressApp.use(express.static(path.join(this.matterbridge.rootDirectory, 'frontend/build')));
|
|
156
102
|
if (!hasParameter('ssl')) {
|
|
157
|
-
// Create an HTTP server and attach the express app
|
|
158
103
|
const http = await import('node:http');
|
|
159
104
|
try {
|
|
160
105
|
this.log.debug(`Creating HTTP server...`);
|
|
@@ -165,7 +110,6 @@ export class Frontend extends EventEmitter {
|
|
|
165
110
|
this.emit('server_error', error);
|
|
166
111
|
return;
|
|
167
112
|
}
|
|
168
|
-
// Listen on the specified port
|
|
169
113
|
if (hasParameter('ingress')) {
|
|
170
114
|
this.httpServer.listen(this.port, '0.0.0.0', () => {
|
|
171
115
|
this.log.info(`The frontend http server is listening on ${UNDERLINE}http://0.0.0.0:${this.port}${UNDERLINEOFF}${rs}`);
|
|
@@ -198,7 +142,6 @@ export class Frontend extends EventEmitter {
|
|
|
198
142
|
});
|
|
199
143
|
}
|
|
200
144
|
else {
|
|
201
|
-
// SSL is enabled, load the certificate and the private key
|
|
202
145
|
let cert;
|
|
203
146
|
let key;
|
|
204
147
|
let ca;
|
|
@@ -208,7 +151,6 @@ export class Frontend extends EventEmitter {
|
|
|
208
151
|
let httpsServerOptions = {};
|
|
209
152
|
const fs = await import('node:fs');
|
|
210
153
|
if (fs.existsSync(path.join(this.matterbridge.matterbridgeDirectory, 'certs/cert.p12'))) {
|
|
211
|
-
// Load the p12 certificate and the passphrase
|
|
212
154
|
try {
|
|
213
155
|
pfx = await fs.promises.readFile(path.join(this.matterbridge.matterbridgeDirectory, 'certs/cert.p12'));
|
|
214
156
|
this.log.info(`Loaded p12 certificate file ${path.join(this.matterbridge.matterbridgeDirectory, 'certs/cert.p12')}`);
|
|
@@ -220,7 +162,7 @@ export class Frontend extends EventEmitter {
|
|
|
220
162
|
}
|
|
221
163
|
try {
|
|
222
164
|
passphrase = await fs.promises.readFile(path.join(this.matterbridge.matterbridgeDirectory, 'certs/cert.pass'), 'utf8');
|
|
223
|
-
passphrase = passphrase.trim();
|
|
165
|
+
passphrase = passphrase.trim();
|
|
224
166
|
this.log.info(`Loaded p12 passphrase file ${path.join(this.matterbridge.matterbridgeDirectory, 'certs/cert.pass')}`);
|
|
225
167
|
}
|
|
226
168
|
catch (error) {
|
|
@@ -231,7 +173,6 @@ export class Frontend extends EventEmitter {
|
|
|
231
173
|
httpsServerOptions = { pfx, passphrase };
|
|
232
174
|
}
|
|
233
175
|
else {
|
|
234
|
-
// 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.
|
|
235
176
|
try {
|
|
236
177
|
cert = await fs.promises.readFile(path.join(this.matterbridge.matterbridgeDirectory, 'certs/cert.pem'), 'utf8');
|
|
237
178
|
this.log.info(`Loaded certificate file ${path.join(this.matterbridge.matterbridgeDirectory, 'certs/cert.pem')}`);
|
|
@@ -261,10 +202,9 @@ export class Frontend extends EventEmitter {
|
|
|
261
202
|
httpsServerOptions = { cert: fullChain ?? cert, key, ca };
|
|
262
203
|
}
|
|
263
204
|
if (hasParameter('mtls')) {
|
|
264
|
-
httpsServerOptions.requestCert = true;
|
|
265
|
-
httpsServerOptions.rejectUnauthorized = true;
|
|
205
|
+
httpsServerOptions.requestCert = true;
|
|
206
|
+
httpsServerOptions.rejectUnauthorized = true;
|
|
266
207
|
}
|
|
267
|
-
// Create an HTTPS server with the SSL certificate and private key (ca is optional) and attach the express app
|
|
268
208
|
const https = await import('node:https');
|
|
269
209
|
try {
|
|
270
210
|
this.log.debug(`Creating HTTPS server...`);
|
|
@@ -275,7 +215,6 @@ export class Frontend extends EventEmitter {
|
|
|
275
215
|
this.emit('server_error', error);
|
|
276
216
|
return;
|
|
277
217
|
}
|
|
278
|
-
// Listen on the specified port
|
|
279
218
|
if (hasParameter('ingress')) {
|
|
280
219
|
this.httpsServer.listen(this.port, '0.0.0.0', () => {
|
|
281
220
|
this.log.info(`The frontend https server is listening on ${UNDERLINE}https://0.0.0.0:${this.port}${UNDERLINEOFF}${rs}`);
|
|
@@ -307,18 +246,16 @@ export class Frontend extends EventEmitter {
|
|
|
307
246
|
return;
|
|
308
247
|
});
|
|
309
248
|
}
|
|
310
|
-
// Create a WebSocket server and attach it to the http or https server
|
|
311
249
|
const ws = await import('ws');
|
|
312
250
|
this.log.debug(`Creating WebSocketServer...`);
|
|
313
251
|
this.webSocketServer = new ws.WebSocketServer(hasParameter('ssl') ? { server: this.httpsServer } : { server: this.httpServer });
|
|
314
252
|
this.webSocketServer.on('connection', (ws, request) => {
|
|
315
253
|
const clientIp = request.socket.remoteAddress;
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
callbackLogLevel = "debug" /* LogLevel.DEBUG */;
|
|
254
|
+
let callbackLogLevel = "notice";
|
|
255
|
+
if (this.matterbridge.getLogLevel() === "info" || Logger.level === MatterLogLevel.INFO)
|
|
256
|
+
callbackLogLevel = "info";
|
|
257
|
+
if (this.matterbridge.getLogLevel() === "debug" || Logger.level === MatterLogLevel.DEBUG)
|
|
258
|
+
callbackLogLevel = "debug";
|
|
322
259
|
AnsiLogger.setGlobalCallback(this.wssSendLogMessage.bind(this), callbackLogLevel);
|
|
323
260
|
this.log.debug(`WebSocketServer logger global callback set to ${callbackLogLevel}`);
|
|
324
261
|
this.log.info(`WebSocketServer client "${clientIp}" connected to Matterbridge`);
|
|
@@ -340,7 +277,6 @@ export class Frontend extends EventEmitter {
|
|
|
340
277
|
}
|
|
341
278
|
});
|
|
342
279
|
ws.on('error', (error) => {
|
|
343
|
-
// istanbul ignore next
|
|
344
280
|
this.log.error(`WebSocket client error: ${error}`);
|
|
345
281
|
});
|
|
346
282
|
});
|
|
@@ -354,7 +290,6 @@ export class Frontend extends EventEmitter {
|
|
|
354
290
|
this.webSocketServer.on('error', (ws, error) => {
|
|
355
291
|
this.log.error(`WebSocketServer error: ${error}`);
|
|
356
292
|
});
|
|
357
|
-
// Subscribe to cli events
|
|
358
293
|
cliEmitter.removeAllListeners();
|
|
359
294
|
cliEmitter.on('uptime', (systemUptime, processUptime) => {
|
|
360
295
|
this.wssSendUptimeUpdate(systemUptime, processUptime);
|
|
@@ -365,8 +300,6 @@ export class Frontend extends EventEmitter {
|
|
|
365
300
|
cliEmitter.on('cpu', (cpuUsage, processCpuUsage) => {
|
|
366
301
|
this.wssSendCpuUpdate(cpuUsage, processCpuUsage);
|
|
367
302
|
});
|
|
368
|
-
// Endpoint to validate login code
|
|
369
|
-
// curl -X POST "http://localhost:8283/api/login" -H "Content-Type: application/json" -d "{\"password\":\"Here\"}"
|
|
370
303
|
this.expressApp.post('/api/login', express.json(), async (req, res) => {
|
|
371
304
|
const { password } = req.body;
|
|
372
305
|
this.log.debug('The frontend sent /api/login', password);
|
|
@@ -385,27 +318,23 @@ export class Frontend extends EventEmitter {
|
|
|
385
318
|
this.log.warn('/api/login error wrong password');
|
|
386
319
|
res.json({ valid: false });
|
|
387
320
|
}
|
|
388
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
389
321
|
}
|
|
390
322
|
catch (error) {
|
|
391
323
|
this.log.error('/api/login error getting password');
|
|
392
324
|
res.json({ valid: false });
|
|
393
325
|
}
|
|
394
326
|
});
|
|
395
|
-
// Endpoint to provide health check for docker
|
|
396
327
|
this.expressApp.get('/health', (req, res) => {
|
|
397
328
|
this.log.debug('Express received /health');
|
|
398
329
|
const healthStatus = {
|
|
399
|
-
status: 'ok',
|
|
400
|
-
uptime: process.uptime(),
|
|
401
|
-
timestamp: new Date().toISOString(),
|
|
330
|
+
status: 'ok',
|
|
331
|
+
uptime: process.uptime(),
|
|
332
|
+
timestamp: new Date().toISOString(),
|
|
402
333
|
};
|
|
403
334
|
res.status(200).json(healthStatus);
|
|
404
335
|
});
|
|
405
|
-
// Endpoint to provide memory usage details
|
|
406
336
|
this.expressApp.get('/memory', async (req, res) => {
|
|
407
337
|
this.log.debug('Express received /memory');
|
|
408
|
-
// Memory usage from process
|
|
409
338
|
const memoryUsageRaw = process.memoryUsage();
|
|
410
339
|
const memoryUsage = {
|
|
411
340
|
rss: formatMemoryUsage(memoryUsageRaw.rss),
|
|
@@ -414,13 +343,10 @@ export class Frontend extends EventEmitter {
|
|
|
414
343
|
external: formatMemoryUsage(memoryUsageRaw.external),
|
|
415
344
|
arrayBuffers: formatMemoryUsage(memoryUsageRaw.arrayBuffers),
|
|
416
345
|
};
|
|
417
|
-
// V8 heap statistics
|
|
418
346
|
const { default: v8 } = await import('node:v8');
|
|
419
347
|
const heapStatsRaw = v8.getHeapStatistics();
|
|
420
348
|
const heapSpacesRaw = v8.getHeapSpaceStatistics();
|
|
421
|
-
// Format heapStats
|
|
422
349
|
const heapStats = Object.fromEntries(Object.entries(heapStatsRaw).map(([key, value]) => [key, formatMemoryUsage(value)]));
|
|
423
|
-
// Format heapSpaces
|
|
424
350
|
const heapSpaces = heapSpacesRaw.map((space) => ({
|
|
425
351
|
...space,
|
|
426
352
|
space_size: formatMemoryUsage(space.space_size),
|
|
@@ -439,22 +365,18 @@ export class Frontend extends EventEmitter {
|
|
|
439
365
|
};
|
|
440
366
|
res.status(200).json(memoryReport);
|
|
441
367
|
});
|
|
442
|
-
// Endpoint to provide settings
|
|
443
368
|
this.expressApp.get('/api/settings', express.json(), async (req, res) => {
|
|
444
369
|
this.log.debug('The frontend sent /api/settings');
|
|
445
370
|
res.json(await this.getApiSettings());
|
|
446
371
|
});
|
|
447
|
-
// Endpoint to provide plugins
|
|
448
372
|
this.expressApp.get('/api/plugins', async (req, res) => {
|
|
449
373
|
this.log.debug('The frontend sent /api/plugins');
|
|
450
374
|
res.json(this.matterbridge.hasCleanupStarted ? [] : this.getPlugins());
|
|
451
375
|
});
|
|
452
|
-
// Endpoint to provide devices
|
|
453
376
|
this.expressApp.get('/api/devices', async (req, res) => {
|
|
454
377
|
this.log.debug('The frontend sent /api/devices');
|
|
455
378
|
res.json(this.matterbridge.hasCleanupStarted ? [] : this.getDevices());
|
|
456
379
|
});
|
|
457
|
-
// Endpoint to view the matterbridge log
|
|
458
380
|
this.expressApp.get('/api/view-mblog', async (req, res) => {
|
|
459
381
|
this.log.debug('The frontend sent /api/view-mblog');
|
|
460
382
|
try {
|
|
@@ -468,7 +390,6 @@ export class Frontend extends EventEmitter {
|
|
|
468
390
|
res.status(500).send('Error reading matterbridge log file. Please enable the matterbridge log on file in the settings.');
|
|
469
391
|
}
|
|
470
392
|
});
|
|
471
|
-
// Endpoint to view the matter.js log
|
|
472
393
|
this.expressApp.get('/api/view-mjlog', async (req, res) => {
|
|
473
394
|
this.log.debug('The frontend sent /api/view-mjlog');
|
|
474
395
|
try {
|
|
@@ -482,7 +403,6 @@ export class Frontend extends EventEmitter {
|
|
|
482
403
|
res.status(500).send('Error reading matter log file. Please enable the matter log on file in the settings.');
|
|
483
404
|
}
|
|
484
405
|
});
|
|
485
|
-
// Endpoint to view the diagnostic.log
|
|
486
406
|
this.expressApp.get('/api/view-diagnostic', async (req, res) => {
|
|
487
407
|
this.log.debug('The frontend sent /api/view-diagnostic');
|
|
488
408
|
await this.generateDiagnostic();
|
|
@@ -493,13 +413,10 @@ export class Frontend extends EventEmitter {
|
|
|
493
413
|
res.send(data.slice(29));
|
|
494
414
|
}
|
|
495
415
|
catch (error) {
|
|
496
|
-
// istanbul ignore next
|
|
497
416
|
this.log.error(`Error reading diagnostic log file ${MATTERBRIDGE_DIAGNOSTIC_FILE}: ${error instanceof Error ? error.message : error}`);
|
|
498
|
-
// istanbul ignore next
|
|
499
417
|
res.status(500).send('Error reading diagnostic log file.');
|
|
500
418
|
}
|
|
501
419
|
});
|
|
502
|
-
// Endpoint to download the diagnostic.log
|
|
503
420
|
this.expressApp.get('/api/download-diagnostic', async (req, res) => {
|
|
504
421
|
this.log.debug(`The frontend sent /api/download-diagnostic`);
|
|
505
422
|
await this.generateDiagnostic();
|
|
@@ -510,19 +427,16 @@ export class Frontend extends EventEmitter {
|
|
|
510
427
|
await fs.promises.writeFile(path.join(os.tmpdir(), MATTERBRIDGE_DIAGNOSTIC_FILE), data, 'utf-8');
|
|
511
428
|
}
|
|
512
429
|
catch (error) {
|
|
513
|
-
// istanbul ignore next
|
|
514
430
|
this.log.debug(`Error in /api/download-diagnostic: ${error instanceof Error ? error.message : error}`);
|
|
515
431
|
}
|
|
516
432
|
res.type('text/plain');
|
|
517
433
|
res.download(path.join(os.tmpdir(), MATTERBRIDGE_DIAGNOSTIC_FILE), MATTERBRIDGE_DIAGNOSTIC_FILE, (error) => {
|
|
518
|
-
/* istanbul ignore if */
|
|
519
434
|
if (error) {
|
|
520
435
|
this.log.error(`Error downloading file ${MATTERBRIDGE_DIAGNOSTIC_FILE}: ${error instanceof Error ? error.message : error}`);
|
|
521
436
|
res.status(500).send('Error downloading the diagnostic log file');
|
|
522
437
|
}
|
|
523
438
|
});
|
|
524
439
|
});
|
|
525
|
-
// Endpoint to view the history.html
|
|
526
440
|
this.expressApp.get('/api/viewhistory', async (req, res) => {
|
|
527
441
|
this.log.debug('The frontend sent /api/viewhistory');
|
|
528
442
|
try {
|
|
@@ -536,7 +450,6 @@ export class Frontend extends EventEmitter {
|
|
|
536
450
|
res.status(500).send('Error reading history file.');
|
|
537
451
|
}
|
|
538
452
|
});
|
|
539
|
-
// Endpoint to download the history.html
|
|
540
453
|
this.expressApp.get('/api/downloadhistory', async (req, res) => {
|
|
541
454
|
this.log.debug(`The frontend sent /api/downloadhistory`);
|
|
542
455
|
try {
|
|
@@ -546,7 +459,6 @@ export class Frontend extends EventEmitter {
|
|
|
546
459
|
await fs.promises.writeFile(path.join(os.tmpdir(), MATTERBRIDGE_HISTORY_FILE), data, 'utf-8');
|
|
547
460
|
res.type('text/plain');
|
|
548
461
|
res.download(path.join(os.tmpdir(), MATTERBRIDGE_HISTORY_FILE), MATTERBRIDGE_HISTORY_FILE, (error) => {
|
|
549
|
-
/* istanbul ignore if */
|
|
550
462
|
if (error) {
|
|
551
463
|
this.log.error(`Error in /api/downloadhistory downloading history file ${MATTERBRIDGE_HISTORY_FILE}: ${error instanceof Error ? error.message : error}`);
|
|
552
464
|
res.status(500).send('Error downloading history file');
|
|
@@ -558,7 +470,6 @@ export class Frontend extends EventEmitter {
|
|
|
558
470
|
res.status(500).send('Error reading history file.');
|
|
559
471
|
}
|
|
560
472
|
});
|
|
561
|
-
// Endpoint to view the shelly log
|
|
562
473
|
this.expressApp.get('/api/shellyviewsystemlog', async (req, res) => {
|
|
563
474
|
this.log.debug('The frontend sent /api/shellyviewsystemlog');
|
|
564
475
|
try {
|
|
@@ -572,7 +483,6 @@ export class Frontend extends EventEmitter {
|
|
|
572
483
|
res.status(500).send('Error reading shelly log file. Please create the shelly system log before loading it.');
|
|
573
484
|
}
|
|
574
485
|
});
|
|
575
|
-
// Endpoint to download the matterbridge log
|
|
576
486
|
this.expressApp.get('/api/download-mblog', async (req, res) => {
|
|
577
487
|
this.log.debug(`The frontend sent /api/download-mblog ${path.join(this.matterbridge.matterbridgeDirectory, MATTERBRIDGE_LOGGER_FILE)}`);
|
|
578
488
|
const fs = await import('node:fs');
|
|
@@ -587,14 +497,12 @@ export class Frontend extends EventEmitter {
|
|
|
587
497
|
}
|
|
588
498
|
res.type('text/plain');
|
|
589
499
|
res.download(path.join(os.tmpdir(), MATTERBRIDGE_LOGGER_FILE), 'matterbridge.log', (error) => {
|
|
590
|
-
/* istanbul ignore if */
|
|
591
500
|
if (error) {
|
|
592
501
|
this.log.error(`Error downloading log file ${MATTERBRIDGE_LOGGER_FILE}: ${error instanceof Error ? error.message : error}`);
|
|
593
502
|
res.status(500).send('Error downloading the matterbridge log file');
|
|
594
503
|
}
|
|
595
504
|
});
|
|
596
505
|
});
|
|
597
|
-
// Endpoint to download the matter log
|
|
598
506
|
this.expressApp.get('/api/download-mjlog', async (req, res) => {
|
|
599
507
|
this.log.debug(`The frontend sent /api/download-mjlog ${path.join(this.matterbridge.matterbridgeDirectory, MATTERBRIDGE_LOGGER_FILE)}`);
|
|
600
508
|
const fs = await import('node:fs');
|
|
@@ -609,14 +517,12 @@ export class Frontend extends EventEmitter {
|
|
|
609
517
|
}
|
|
610
518
|
res.type('text/plain');
|
|
611
519
|
res.download(path.join(os.tmpdir(), MATTER_LOGGER_FILE), 'matter.log', (error) => {
|
|
612
|
-
/* istanbul ignore if */
|
|
613
520
|
if (error) {
|
|
614
521
|
this.log.error(`Error downloading log file ${MATTER_LOGGER_FILE}: ${error instanceof Error ? error.message : error}`);
|
|
615
522
|
res.status(500).send('Error downloading the matter log file');
|
|
616
523
|
}
|
|
617
524
|
});
|
|
618
525
|
});
|
|
619
|
-
// Endpoint to download the shelly log
|
|
620
526
|
this.expressApp.get('/api/shellydownloadsystemlog', async (req, res) => {
|
|
621
527
|
this.log.debug('The frontend sent /api/shellydownloadsystemlog');
|
|
622
528
|
const fs = await import('node:fs');
|
|
@@ -631,91 +537,75 @@ export class Frontend extends EventEmitter {
|
|
|
631
537
|
}
|
|
632
538
|
res.type('text/plain');
|
|
633
539
|
res.download(path.join(os.tmpdir(), 'shelly.log'), 'shelly.log', (error) => {
|
|
634
|
-
/* istanbul ignore if */
|
|
635
540
|
if (error) {
|
|
636
541
|
this.log.error(`Error downloading Shelly system log file: ${error instanceof Error ? error.message : error}`);
|
|
637
542
|
res.status(500).send('Error downloading Shelly system log file');
|
|
638
543
|
}
|
|
639
544
|
});
|
|
640
545
|
});
|
|
641
|
-
// Endpoint to download the matterbridge storage directory
|
|
642
546
|
this.expressApp.get('/api/download-mbstorage', async (req, res) => {
|
|
643
547
|
this.log.debug('The frontend sent /api/download-mbstorage');
|
|
644
548
|
await createZip(path.join(os.tmpdir(), `matterbridge.${NODE_STORAGE_DIR}.zip`), path.join(this.matterbridge.matterbridgeDirectory, NODE_STORAGE_DIR));
|
|
645
549
|
res.download(path.join(os.tmpdir(), `matterbridge.${NODE_STORAGE_DIR}.zip`), `matterbridge.${NODE_STORAGE_DIR}.zip`, (error) => {
|
|
646
|
-
/* istanbul ignore if */
|
|
647
550
|
if (error) {
|
|
648
551
|
this.log.error(`Error downloading file ${`matterbridge.${NODE_STORAGE_DIR}.zip`}: ${error instanceof Error ? error.message : error}`);
|
|
649
552
|
res.status(500).send('Error downloading the matterbridge storage file');
|
|
650
553
|
}
|
|
651
554
|
});
|
|
652
555
|
});
|
|
653
|
-
// Endpoint to download the matter storage file
|
|
654
556
|
this.expressApp.get('/api/download-mjstorage', async (req, res) => {
|
|
655
557
|
this.log.debug('The frontend sent /api/download-mjstorage');
|
|
656
558
|
await createZip(path.join(os.tmpdir(), `matterbridge.${MATTER_STORAGE_NAME}.zip`), path.join(this.matterbridge.matterbridgeDirectory, MATTER_STORAGE_NAME));
|
|
657
559
|
res.download(path.join(os.tmpdir(), `matterbridge.${MATTER_STORAGE_NAME}.zip`), `matterbridge.${MATTER_STORAGE_NAME}.zip`, (error) => {
|
|
658
|
-
/* istanbul ignore if */
|
|
659
560
|
if (error) {
|
|
660
561
|
this.log.error(`Error downloading the matter storage matterbridge.${MATTER_STORAGE_NAME}.zip: ${error instanceof Error ? error.message : error}`);
|
|
661
562
|
res.status(500).send('Error downloading the matter storage zip file');
|
|
662
563
|
}
|
|
663
564
|
});
|
|
664
565
|
});
|
|
665
|
-
// Endpoint to download the matterbridge plugin directory
|
|
666
566
|
this.expressApp.get('/api/download-pluginstorage', async (req, res) => {
|
|
667
567
|
this.log.debug('The frontend sent /api/download-pluginstorage');
|
|
668
568
|
await createZip(path.join(os.tmpdir(), `matterbridge.pluginstorage.zip`), this.matterbridge.matterbridgePluginDirectory);
|
|
669
569
|
res.download(path.join(os.tmpdir(), `matterbridge.pluginstorage.zip`), `matterbridge.pluginstorage.zip`, (error) => {
|
|
670
|
-
/* istanbul ignore if */
|
|
671
570
|
if (error) {
|
|
672
571
|
this.log.error(`Error downloading file matterbridge.pluginstorage.zip: ${error instanceof Error ? error.message : error}`);
|
|
673
572
|
res.status(500).send('Error downloading the matterbridge plugin storage file');
|
|
674
573
|
}
|
|
675
574
|
});
|
|
676
575
|
});
|
|
677
|
-
// Endpoint to download the matterbridge plugin config files
|
|
678
576
|
this.expressApp.get('/api/download-pluginconfig', async (req, res) => {
|
|
679
577
|
this.log.debug('The frontend sent /api/download-pluginconfig');
|
|
680
578
|
await createZip(path.join(os.tmpdir(), `matterbridge.pluginconfig.zip`), path.relative(process.cwd(), path.join(this.matterbridge.matterbridgeDirectory, '*.config.json')));
|
|
681
579
|
res.download(path.join(os.tmpdir(), `matterbridge.pluginconfig.zip`), `matterbridge.pluginconfig.zip`, (error) => {
|
|
682
|
-
/* istanbul ignore if */
|
|
683
580
|
if (error) {
|
|
684
581
|
this.log.error(`Error downloading file matterbridge.pluginconfig.zip: ${error instanceof Error ? error.message : error}`);
|
|
685
582
|
res.status(500).send('Error downloading the matterbridge plugin config file');
|
|
686
583
|
}
|
|
687
584
|
});
|
|
688
585
|
});
|
|
689
|
-
// Endpoint to download the matterbridge backup (created with the backup command)
|
|
690
586
|
this.expressApp.get('/api/download-backup', async (req, res) => {
|
|
691
587
|
this.log.debug('The frontend sent /api/download-backup');
|
|
692
588
|
res.download(path.join(os.tmpdir(), `matterbridge.backup.zip`), `matterbridge.backup.zip`, (error) => {
|
|
693
|
-
/* istanbul ignore if */
|
|
694
589
|
if (error) {
|
|
695
590
|
this.log.error(`Error downloading file matterbridge.backup.zip: ${error instanceof Error ? error.message : error}`);
|
|
696
591
|
res.status(500).send(`Error downloading file matterbridge.backup.zip: ${error instanceof Error ? error.message : error}`);
|
|
697
592
|
}
|
|
698
593
|
});
|
|
699
594
|
});
|
|
700
|
-
// Endpoint to upload a package
|
|
701
595
|
this.expressApp.post('/api/uploadpackage', upload.single('file'), async (req, res) => {
|
|
702
596
|
const { filename } = req.body;
|
|
703
597
|
const file = req.file;
|
|
704
|
-
/* istanbul ignore if */
|
|
705
598
|
if (!file || !filename) {
|
|
706
599
|
this.log.error(`uploadpackage: invalid request: file and filename are required`);
|
|
707
600
|
res.status(400).send('Invalid request: file and filename are required');
|
|
708
601
|
return;
|
|
709
602
|
}
|
|
710
603
|
this.wssSendSnackbarMessage(`Installing package ${filename}. Please wait...`, 0);
|
|
711
|
-
// Define the path where the plugin file will be saved
|
|
712
604
|
const filePath = path.join(this.matterbridge.matterbridgeDirectory, 'uploads', filename);
|
|
713
605
|
try {
|
|
714
|
-
// Move the uploaded file to the specified path
|
|
715
606
|
const fs = await import('node:fs');
|
|
716
607
|
await fs.promises.rename(file.path, filePath);
|
|
717
608
|
this.log.info(`File ${plg}${filename}${nf} uploaded successfully`);
|
|
718
|
-
// Install the plugin package
|
|
719
609
|
if (filename.endsWith('.tgz')) {
|
|
720
610
|
const { spawnCommand } = await import('./utils/spawn.js');
|
|
721
611
|
await spawnCommand(this.matterbridge, 'npm', ['install', '-g', filePath, '--omit=dev', '--verbose'], 'install', filename);
|
|
@@ -735,7 +625,6 @@ export class Frontend extends EventEmitter {
|
|
|
735
625
|
res.status(500).send(`Error uploading or installing plugin package ${filename}`);
|
|
736
626
|
}
|
|
737
627
|
});
|
|
738
|
-
// Fallback for routing (must be the last route)
|
|
739
628
|
this.expressApp.use((req, res) => {
|
|
740
629
|
this.log.debug(`The frontend sent ${req.url} method ${req.method}: sending index.html as fallback`);
|
|
741
630
|
res.sendFile(path.join(this.matterbridge.rootDirectory, 'frontend/build/index.html'));
|
|
@@ -745,16 +634,13 @@ export class Frontend extends EventEmitter {
|
|
|
745
634
|
async stop() {
|
|
746
635
|
this.log.debug('Stopping the frontend...');
|
|
747
636
|
const ws = await import('ws');
|
|
748
|
-
// Remove listeners from the express app
|
|
749
637
|
if (this.expressApp) {
|
|
750
638
|
this.expressApp.removeAllListeners();
|
|
751
639
|
this.expressApp = undefined;
|
|
752
640
|
this.log.debug('Frontend app closed successfully');
|
|
753
641
|
}
|
|
754
|
-
// Close the WebSocket server
|
|
755
642
|
if (this.webSocketServer) {
|
|
756
643
|
this.log.debug('Closing WebSocket server...');
|
|
757
|
-
// Close all active connections
|
|
758
644
|
this.webSocketServer.clients.forEach((client) => {
|
|
759
645
|
if (client.readyState === ws.WebSocket.OPEN) {
|
|
760
646
|
client.close();
|
|
@@ -763,7 +649,6 @@ export class Frontend extends EventEmitter {
|
|
|
763
649
|
await withTimeout(new Promise((resolve) => {
|
|
764
650
|
this.webSocketServer?.close((error) => {
|
|
765
651
|
if (error) {
|
|
766
|
-
// istanbul ignore next
|
|
767
652
|
this.log.error(`Error closing WebSocket server: ${error}`);
|
|
768
653
|
}
|
|
769
654
|
else {
|
|
@@ -776,27 +661,8 @@ export class Frontend extends EventEmitter {
|
|
|
776
661
|
this.webSocketServer.removeAllListeners();
|
|
777
662
|
this.webSocketServer = undefined;
|
|
778
663
|
}
|
|
779
|
-
// Close the http server
|
|
780
664
|
if (this.httpServer) {
|
|
781
665
|
this.log.debug('Closing http server...');
|
|
782
|
-
/*
|
|
783
|
-
await withTimeout(
|
|
784
|
-
new Promise<void>((resolve) => {
|
|
785
|
-
this.httpServer?.close((error) => {
|
|
786
|
-
if (error) {
|
|
787
|
-
// istanbul ignore next
|
|
788
|
-
this.log.error(`Error closing http server: ${error}`);
|
|
789
|
-
} else {
|
|
790
|
-
this.log.debug('Http server closed successfully');
|
|
791
|
-
this.emit('server_stopped');
|
|
792
|
-
}
|
|
793
|
-
resolve();
|
|
794
|
-
});
|
|
795
|
-
}),
|
|
796
|
-
5000,
|
|
797
|
-
false,
|
|
798
|
-
);
|
|
799
|
-
*/
|
|
800
666
|
this.httpServer.close();
|
|
801
667
|
this.log.debug('Http server closed successfully');
|
|
802
668
|
this.listening = false;
|
|
@@ -805,27 +671,8 @@ export class Frontend extends EventEmitter {
|
|
|
805
671
|
this.httpServer = undefined;
|
|
806
672
|
this.log.debug('Frontend http server closed successfully');
|
|
807
673
|
}
|
|
808
|
-
// Close the https server
|
|
809
674
|
if (this.httpsServer) {
|
|
810
675
|
this.log.debug('Closing https server...');
|
|
811
|
-
/*
|
|
812
|
-
await withTimeout(
|
|
813
|
-
new Promise<void>((resolve) => {
|
|
814
|
-
this.httpsServer?.close((error) => {
|
|
815
|
-
if (error) {
|
|
816
|
-
// istanbul ignore next
|
|
817
|
-
this.log.error(`Error closing https server: ${error}`);
|
|
818
|
-
} else {
|
|
819
|
-
this.log.debug('Https server closed successfully');
|
|
820
|
-
this.emit('server_stopped');
|
|
821
|
-
}
|
|
822
|
-
resolve();
|
|
823
|
-
});
|
|
824
|
-
}),
|
|
825
|
-
5000,
|
|
826
|
-
false,
|
|
827
|
-
);
|
|
828
|
-
*/
|
|
829
676
|
this.httpsServer.close();
|
|
830
677
|
this.log.debug('Https server closed successfully');
|
|
831
678
|
this.listening = false;
|
|
@@ -836,13 +683,7 @@ export class Frontend extends EventEmitter {
|
|
|
836
683
|
}
|
|
837
684
|
this.log.debug('Frontend stopped successfully');
|
|
838
685
|
}
|
|
839
|
-
/**
|
|
840
|
-
* Retrieves the api settings data.
|
|
841
|
-
*
|
|
842
|
-
* @returns {Promise<{ matterbridgeInformation: MatterbridgeInformation, systemInformation: SystemInformation }>} A promise that resolve in the api settings object.
|
|
843
|
-
*/
|
|
844
686
|
async getApiSettings() {
|
|
845
|
-
// Update the variable system information properties
|
|
846
687
|
this.matterbridge.systemInformation.totalMemory = formatMemoryUsage(os.totalmem());
|
|
847
688
|
this.matterbridge.systemInformation.freeMemory = formatMemoryUsage(os.freemem());
|
|
848
689
|
this.matterbridge.systemInformation.systemUptime = formatOsUpTime(os.uptime());
|
|
@@ -852,7 +693,6 @@ export class Frontend extends EventEmitter {
|
|
|
852
693
|
this.matterbridge.systemInformation.rss = formatMemoryUsage(process.memoryUsage().rss);
|
|
853
694
|
this.matterbridge.systemInformation.heapTotal = formatMemoryUsage(process.memoryUsage().heapTotal);
|
|
854
695
|
this.matterbridge.systemInformation.heapUsed = formatMemoryUsage(process.memoryUsage().heapUsed);
|
|
855
|
-
// Create the matterbridge information
|
|
856
696
|
const info = {
|
|
857
697
|
homeDirectory: this.matterbridge.homeDirectory,
|
|
858
698
|
rootDirectory: this.matterbridge.rootDirectory,
|
|
@@ -888,15 +728,9 @@ export class Frontend extends EventEmitter {
|
|
|
888
728
|
};
|
|
889
729
|
return { systemInformation: this.matterbridge.systemInformation, matterbridgeInformation: info };
|
|
890
730
|
}
|
|
891
|
-
/**
|
|
892
|
-
* Retrieves the reachable attribute.
|
|
893
|
-
*
|
|
894
|
-
* @param {MatterbridgeEndpoint} device - The MatterbridgeEndpoint object.
|
|
895
|
-
* @returns {boolean} The reachable attribute.
|
|
896
|
-
*/
|
|
897
731
|
getReachability(device) {
|
|
898
732
|
if (this.matterbridge.hasCleanupStarted)
|
|
899
|
-
return false;
|
|
733
|
+
return false;
|
|
900
734
|
if (!device.lifecycle.isReady || device.construction.status !== Lifecycle.Status.Active)
|
|
901
735
|
return false;
|
|
902
736
|
if (device.hasClusterServer(BridgedDeviceBasicInformation.Cluster.id))
|
|
@@ -907,15 +741,9 @@ export class Frontend extends EventEmitter {
|
|
|
907
741
|
return true;
|
|
908
742
|
return false;
|
|
909
743
|
}
|
|
910
|
-
/**
|
|
911
|
-
* Retrieves the power source attribute.
|
|
912
|
-
*
|
|
913
|
-
* @param {MatterbridgeEndpoint} endpoint - The MatterbridgeDevice to retrieve the power source from.
|
|
914
|
-
* @returns {'ac' | 'dc' | 'ok' | 'warning' | 'critical' | undefined} The power source attribute.
|
|
915
|
-
*/
|
|
916
744
|
getPowerSource(endpoint) {
|
|
917
745
|
if (this.matterbridge.hasCleanupStarted)
|
|
918
|
-
return;
|
|
746
|
+
return;
|
|
919
747
|
if (!endpoint.lifecycle.isReady || endpoint.construction.status !== Lifecycle.Status.Active)
|
|
920
748
|
return undefined;
|
|
921
749
|
const powerSource = (device) => {
|
|
@@ -930,25 +758,16 @@ export class Frontend extends EventEmitter {
|
|
|
930
758
|
}
|
|
931
759
|
return;
|
|
932
760
|
};
|
|
933
|
-
// Root endpoint
|
|
934
761
|
if (endpoint.hasClusterServer(PowerSource.Cluster.id))
|
|
935
762
|
return powerSource(endpoint);
|
|
936
|
-
// Child endpoints
|
|
937
763
|
for (const child of endpoint.getChildEndpoints()) {
|
|
938
764
|
if (child.hasClusterServer(PowerSource.Cluster.id))
|
|
939
765
|
return powerSource(child);
|
|
940
766
|
}
|
|
941
767
|
}
|
|
942
|
-
/**
|
|
943
|
-
* Retrieves the cluster text description from a given device.
|
|
944
|
-
* The output is a string with the attributes description of the cluster servers in the device to show in the frontend.
|
|
945
|
-
*
|
|
946
|
-
* @param {MatterbridgeEndpoint} device - The MatterbridgeEndpoint to retrieve the cluster text from.
|
|
947
|
-
* @returns {string} The attributes description of the cluster servers in the device.
|
|
948
|
-
*/
|
|
949
768
|
getClusterTextFromDevice(device) {
|
|
950
769
|
if (this.matterbridge.hasCleanupStarted)
|
|
951
|
-
return '';
|
|
770
|
+
return '';
|
|
952
771
|
if (!device.lifecycle.isReady || device.construction.status !== Lifecycle.Status.Active)
|
|
953
772
|
return '';
|
|
954
773
|
const getUserLabel = (device) => {
|
|
@@ -958,7 +777,6 @@ export class Frontend extends EventEmitter {
|
|
|
958
777
|
if (composed)
|
|
959
778
|
return 'Composed: ' + composed.value;
|
|
960
779
|
}
|
|
961
|
-
// istanbul ignore next cause is not reachable
|
|
962
780
|
return '';
|
|
963
781
|
};
|
|
964
782
|
const getFixedLabel = (device) => {
|
|
@@ -968,13 +786,11 @@ export class Frontend extends EventEmitter {
|
|
|
968
786
|
if (composed)
|
|
969
787
|
return 'Composed: ' + composed.value;
|
|
970
788
|
}
|
|
971
|
-
// istanbul ignore next cause is not reacheable
|
|
972
789
|
return '';
|
|
973
790
|
};
|
|
974
791
|
let attributes = '';
|
|
975
792
|
let supportedModes = [];
|
|
976
793
|
device.forEachAttribute((clusterName, clusterId, attributeName, attributeId, attributeValue) => {
|
|
977
|
-
// console.log(`${device.deviceName} => Cluster: ${clusterName}-${clusterId} Attribute: ${attributeName}-${attributeId} Value(${typeof attributeValue}): ${attributeValue}`);
|
|
978
794
|
if (typeof attributeValue === 'undefined' || attributeValue === undefined)
|
|
979
795
|
return;
|
|
980
796
|
if (clusterName === 'onOff' && attributeName === 'onOff')
|
|
@@ -1064,17 +880,11 @@ export class Frontend extends EventEmitter {
|
|
|
1064
880
|
if (clusterName === 'userLabel' && attributeName === 'labelList')
|
|
1065
881
|
attributes += `${getUserLabel(device)} `;
|
|
1066
882
|
});
|
|
1067
|
-
// console.log(`${device.deviceName}.forEachAttribute: ${attributes}`);
|
|
1068
883
|
return attributes.trimStart().trimEnd();
|
|
1069
884
|
}
|
|
1070
|
-
/**
|
|
1071
|
-
* Retrieves the registered plugins sanitized for res.json().
|
|
1072
|
-
*
|
|
1073
|
-
* @returns {ApiPlugin[]} An array of BaseRegisteredPlugin.
|
|
1074
|
-
*/
|
|
1075
885
|
getPlugins() {
|
|
1076
886
|
if (this.matterbridge.hasCleanupStarted)
|
|
1077
|
-
return [];
|
|
887
|
+
return [];
|
|
1078
888
|
const plugins = [];
|
|
1079
889
|
for (const plugin of this.matterbridge.plugins.array()) {
|
|
1080
890
|
plugins.push({
|
|
@@ -1102,27 +912,18 @@ export class Frontend extends EventEmitter {
|
|
|
1102
912
|
schemaJson: plugin.schemaJson,
|
|
1103
913
|
hasWhiteList: plugin.configJson?.whiteList !== undefined,
|
|
1104
914
|
hasBlackList: plugin.configJson?.blackList !== undefined,
|
|
1105
|
-
// Childbridge mode specific data
|
|
1106
915
|
matter: plugin.serverNode ? this.matterbridge.getServerNodeData(plugin.serverNode) : undefined,
|
|
1107
916
|
});
|
|
1108
917
|
}
|
|
1109
918
|
return plugins;
|
|
1110
919
|
}
|
|
1111
|
-
/**
|
|
1112
|
-
* Retrieves the devices from Matterbridge.
|
|
1113
|
-
*
|
|
1114
|
-
* @param {string} [pluginName] - The name of the plugin to filter devices by.
|
|
1115
|
-
* @returns {ApiDevice[]} An array of ApiDevices for the frontend.
|
|
1116
|
-
*/
|
|
1117
920
|
getDevices(pluginName) {
|
|
1118
921
|
if (this.matterbridge.hasCleanupStarted)
|
|
1119
|
-
return [];
|
|
922
|
+
return [];
|
|
1120
923
|
const devices = [];
|
|
1121
924
|
for (const device of this.matterbridge.devices.array()) {
|
|
1122
|
-
// Filter by pluginName if provided
|
|
1123
925
|
if (pluginName && pluginName !== device.plugin)
|
|
1124
926
|
continue;
|
|
1125
|
-
// Check if the device has the required properties
|
|
1126
927
|
if (!device.plugin || !device.deviceType || !device.name || !device.deviceName || !device.serialNumber || !device.uniqueId || !device.lifecycle.isReady)
|
|
1127
928
|
continue;
|
|
1128
929
|
devices.push({
|
|
@@ -1142,39 +943,24 @@ export class Frontend extends EventEmitter {
|
|
|
1142
943
|
}
|
|
1143
944
|
return devices;
|
|
1144
945
|
}
|
|
1145
|
-
/**
|
|
1146
|
-
* Retrieves the clusters from a given plugin and endpoint number.
|
|
1147
|
-
*
|
|
1148
|
-
* Response for /api/clusters
|
|
1149
|
-
*
|
|
1150
|
-
* @param {string} pluginName - The name of the plugin.
|
|
1151
|
-
* @param {number} endpointNumber - The endpoint number.
|
|
1152
|
-
* @returns {ApiClusters | undefined} A promise that resolves to the clusters or undefined if not found.
|
|
1153
|
-
*/
|
|
1154
946
|
getClusters(pluginName, endpointNumber) {
|
|
1155
947
|
if (this.matterbridge.hasCleanupStarted)
|
|
1156
|
-
return;
|
|
948
|
+
return;
|
|
1157
949
|
const endpoint = this.matterbridge.devices.array().find((d) => d.plugin === pluginName && d.maybeNumber === endpointNumber);
|
|
1158
950
|
if (!endpoint || !endpoint.plugin || !endpoint.maybeNumber || !endpoint.maybeId || !endpoint.deviceName || !endpoint.serialNumber) {
|
|
1159
951
|
this.log.error(`getClusters: no device found for plugin ${pluginName} and endpoint number ${endpointNumber}`);
|
|
1160
952
|
return;
|
|
1161
953
|
}
|
|
1162
|
-
// this.log.debug(`***getClusters: getting clusters for device ${endpoint.deviceName} plugin ${pluginName} endpoint number ${endpointNumber}`);
|
|
1163
|
-
// Get the device types from the main endpoint
|
|
1164
954
|
const deviceTypes = [];
|
|
1165
955
|
const clusters = [];
|
|
1166
956
|
endpoint.state.descriptor.deviceTypeList.forEach((d) => {
|
|
1167
957
|
deviceTypes.push(d.deviceType);
|
|
1168
958
|
});
|
|
1169
|
-
// Get the clusters from the main endpoint
|
|
1170
959
|
endpoint.forEachAttribute((clusterName, clusterId, attributeName, attributeId, attributeValue) => {
|
|
1171
960
|
if (typeof attributeValue === 'undefined' || attributeValue === undefined)
|
|
1172
961
|
return;
|
|
1173
962
|
if (clusterName === 'EveHistory' && ['configDataGet', 'configDataSet', 'historyStatus', 'historyEntries', 'historyRequest', 'historySetTime', 'rLoc'].includes(attributeName))
|
|
1174
963
|
return;
|
|
1175
|
-
// console.log(
|
|
1176
|
-
// `${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}`,
|
|
1177
|
-
// );
|
|
1178
964
|
clusters.push({
|
|
1179
965
|
endpoint: endpoint.number.toString(),
|
|
1180
966
|
number: endpoint.number,
|
|
@@ -1188,19 +974,12 @@ export class Frontend extends EventEmitter {
|
|
|
1188
974
|
attributeLocalValue: attributeValue,
|
|
1189
975
|
});
|
|
1190
976
|
});
|
|
1191
|
-
// Get the child endpoints
|
|
1192
977
|
const childEndpoints = endpoint.getChildEndpoints();
|
|
1193
|
-
// if (childEndpoints.length === 0) {
|
|
1194
|
-
// this.log.debug(`***getClusters: found ${childEndpoints.length} child endpoints for device ${endpoint.deviceName} plugin ${pluginName} and endpoint number ${endpointNumber}`);
|
|
1195
|
-
// }
|
|
1196
978
|
childEndpoints.forEach((childEndpoint) => {
|
|
1197
|
-
// istanbul ignore if cause is not reachable: should never happen but ...
|
|
1198
979
|
if (!childEndpoint.maybeId || !childEndpoint.maybeNumber) {
|
|
1199
980
|
this.log.error(`getClusters: no child endpoint found for plugin ${pluginName} and endpoint number ${endpointNumber}`);
|
|
1200
981
|
return;
|
|
1201
982
|
}
|
|
1202
|
-
// this.log.debug(`***getClusters: getting clusters for child endpoint ${childEndpoint.id} of device ${endpoint.deviceName} plugin ${pluginName} endpoint number ${childEndpoint.number}`);
|
|
1203
|
-
// Get the device types of the child endpoint
|
|
1204
983
|
const deviceTypes = [];
|
|
1205
984
|
childEndpoint.state.descriptor.deviceTypeList.forEach((d) => {
|
|
1206
985
|
deviceTypes.push(d.deviceType);
|
|
@@ -1210,9 +989,6 @@ export class Frontend extends EventEmitter {
|
|
|
1210
989
|
return;
|
|
1211
990
|
if (clusterName === 'EveHistory' && ['configDataGet', 'configDataSet', 'historyStatus', 'historyEntries', 'historyRequest', 'historySetTime', 'rLoc'].includes(attributeName))
|
|
1212
991
|
return;
|
|
1213
|
-
// console.log(
|
|
1214
|
-
// `${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}`,
|
|
1215
|
-
// );
|
|
1216
992
|
clusters.push({
|
|
1217
993
|
endpoint: childEndpoint.number.toString(),
|
|
1218
994
|
number: childEndpoint.number,
|
|
@@ -1232,7 +1008,6 @@ export class Frontend extends EventEmitter {
|
|
|
1232
1008
|
async generateDiagnostic() {
|
|
1233
1009
|
this.log.debug('Generating diagnostic...');
|
|
1234
1010
|
const serverNodes = [];
|
|
1235
|
-
// istanbul ignore else
|
|
1236
1011
|
if (this.matterbridge.bridgeMode === 'bridge') {
|
|
1237
1012
|
if (this.matterbridge.serverNode)
|
|
1238
1013
|
serverNodes.push(this.matterbridge.serverNode);
|
|
@@ -1243,7 +1018,6 @@ export class Frontend extends EventEmitter {
|
|
|
1243
1018
|
serverNodes.push(plugin.serverNode);
|
|
1244
1019
|
}
|
|
1245
1020
|
}
|
|
1246
|
-
// istanbul ignore next
|
|
1247
1021
|
for (const device of this.matterbridge.devices.array()) {
|
|
1248
1022
|
if (device.serverNode)
|
|
1249
1023
|
serverNodes.push(device.serverNode);
|
|
@@ -1267,15 +1041,8 @@ export class Frontend extends EventEmitter {
|
|
|
1267
1041
|
values: [...serverNodes],
|
|
1268
1042
|
})));
|
|
1269
1043
|
delete Logger.destinations.diagnostic;
|
|
1270
|
-
await wait(500);
|
|
1044
|
+
await wait(500);
|
|
1271
1045
|
}
|
|
1272
|
-
/**
|
|
1273
|
-
* Handles incoming websocket api request messages from the Matterbridge frontend.
|
|
1274
|
-
*
|
|
1275
|
-
* @param {WebSocket} client - The websocket client that sent the message.
|
|
1276
|
-
* @param {WebSocket.RawData} message - The raw data of the message received from the client.
|
|
1277
|
-
* @returns {Promise<void>} A promise that resolves when the message has been handled.
|
|
1278
|
-
*/
|
|
1279
1046
|
async wsMessageHandler(client, message) {
|
|
1280
1047
|
let data;
|
|
1281
1048
|
const sendResponse = (data) => {
|
|
@@ -1295,7 +1062,7 @@ export class Frontend extends EventEmitter {
|
|
|
1295
1062
|
};
|
|
1296
1063
|
try {
|
|
1297
1064
|
data = JSON.parse(message.toString());
|
|
1298
|
-
if (!isValidNumber(data.id) || !isValidString(data.dst) || !isValidString(data.src) || !isValidString(data.method)
|
|
1065
|
+
if (!isValidNumber(data.id) || !isValidString(data.dst) || !isValidString(data.src) || !isValidString(data.method) || data.dst !== 'Matterbridge') {
|
|
1299
1066
|
this.log.error(`Invalid message from websocket client: ${debugStringify(data)}`);
|
|
1300
1067
|
sendResponse({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, error: 'Invalid message' });
|
|
1301
1068
|
return;
|
|
@@ -1369,7 +1136,6 @@ export class Frontend extends EventEmitter {
|
|
|
1369
1136
|
return;
|
|
1370
1137
|
})
|
|
1371
1138
|
.catch((_error) => {
|
|
1372
|
-
//
|
|
1373
1139
|
});
|
|
1374
1140
|
}
|
|
1375
1141
|
else {
|
|
@@ -1417,7 +1183,6 @@ export class Frontend extends EventEmitter {
|
|
|
1417
1183
|
return;
|
|
1418
1184
|
})
|
|
1419
1185
|
.catch((_error) => {
|
|
1420
|
-
//
|
|
1421
1186
|
});
|
|
1422
1187
|
}
|
|
1423
1188
|
sendResponse({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, success: true });
|
|
@@ -1443,7 +1208,6 @@ export class Frontend extends EventEmitter {
|
|
|
1443
1208
|
const plugin = this.matterbridge.plugins.get(data.params.pluginName);
|
|
1444
1209
|
await this.matterbridge.plugins.shutdown(plugin, 'The plugin is restarting.', false, true);
|
|
1445
1210
|
if (plugin.serverNode) {
|
|
1446
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1447
1211
|
await this.matterbridge.stopServerNode(plugin.serverNode);
|
|
1448
1212
|
plugin.serverNode = undefined;
|
|
1449
1213
|
}
|
|
@@ -1453,20 +1217,18 @@ export class Frontend extends EventEmitter {
|
|
|
1453
1217
|
this.matterbridge.devices.remove(device);
|
|
1454
1218
|
}
|
|
1455
1219
|
}
|
|
1456
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1457
1220
|
if (plugin.type === 'DynamicPlatform' && !plugin.locked)
|
|
1458
1221
|
await this.matterbridge.createDynamicPlugin(plugin);
|
|
1459
1222
|
await this.matterbridge.plugins.load(plugin, true, 'The plugin has been restarted', true);
|
|
1460
|
-
plugin.restartRequired = false;
|
|
1223
|
+
plugin.restartRequired = false;
|
|
1461
1224
|
let needRestart = 0;
|
|
1462
1225
|
for (const plugin of this.matterbridge.plugins) {
|
|
1463
1226
|
if (plugin.restartRequired)
|
|
1464
1227
|
needRestart++;
|
|
1465
1228
|
}
|
|
1466
1229
|
if (needRestart === 0) {
|
|
1467
|
-
this.wssSendRestartNotRequired(true);
|
|
1230
|
+
this.wssSendRestartNotRequired(true);
|
|
1468
1231
|
}
|
|
1469
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1470
1232
|
if (plugin.serverNode)
|
|
1471
1233
|
await this.matterbridge.startServerNode(plugin.serverNode);
|
|
1472
1234
|
this.wssSendSnackbarMessage(`Restarted plugin ${data.params.pluginName}`, 5, 'success');
|
|
@@ -1731,22 +1493,22 @@ export class Frontend extends EventEmitter {
|
|
|
1731
1493
|
if (isValidString(data.params.value, 4)) {
|
|
1732
1494
|
this.log.debug('Matterbridge logger level:', data.params.value);
|
|
1733
1495
|
if (data.params.value === 'Debug') {
|
|
1734
|
-
await this.matterbridge.setLogLevel("debug"
|
|
1496
|
+
await this.matterbridge.setLogLevel("debug");
|
|
1735
1497
|
}
|
|
1736
1498
|
else if (data.params.value === 'Info') {
|
|
1737
|
-
await this.matterbridge.setLogLevel("info"
|
|
1499
|
+
await this.matterbridge.setLogLevel("info");
|
|
1738
1500
|
}
|
|
1739
1501
|
else if (data.params.value === 'Notice') {
|
|
1740
|
-
await this.matterbridge.setLogLevel("notice"
|
|
1502
|
+
await this.matterbridge.setLogLevel("notice");
|
|
1741
1503
|
}
|
|
1742
1504
|
else if (data.params.value === 'Warn') {
|
|
1743
|
-
await this.matterbridge.setLogLevel("warn"
|
|
1505
|
+
await this.matterbridge.setLogLevel("warn");
|
|
1744
1506
|
}
|
|
1745
1507
|
else if (data.params.value === 'Error') {
|
|
1746
|
-
await this.matterbridge.setLogLevel("error"
|
|
1508
|
+
await this.matterbridge.setLogLevel("error");
|
|
1747
1509
|
}
|
|
1748
1510
|
else if (data.params.value === 'Fatal') {
|
|
1749
|
-
await this.matterbridge.setLogLevel("fatal"
|
|
1511
|
+
await this.matterbridge.setLogLevel("fatal");
|
|
1750
1512
|
}
|
|
1751
1513
|
await this.matterbridge.nodeContext?.set('matterbridgeLogLevel', this.log.logLevel);
|
|
1752
1514
|
sendResponse({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, success: true });
|
|
@@ -1757,7 +1519,6 @@ export class Frontend extends EventEmitter {
|
|
|
1757
1519
|
this.log.debug('Matterbridge file log:', data.params.value);
|
|
1758
1520
|
this.matterbridge.fileLogger = data.params.value;
|
|
1759
1521
|
await this.matterbridge.nodeContext?.set('matterbridgeFileLog', data.params.value);
|
|
1760
|
-
// Create the file logger for matterbridge
|
|
1761
1522
|
if (data.params.value)
|
|
1762
1523
|
AnsiLogger.setGlobalLogfile(path.join(this.matterbridge.matterbridgeDirectory, MATTERBRIDGE_LOGGER_FILE), await this.matterbridge.getLogLevel(), true);
|
|
1763
1524
|
else
|
|
@@ -1786,12 +1547,11 @@ export class Frontend extends EventEmitter {
|
|
|
1786
1547
|
else if (data.params.value === 'Fatal') {
|
|
1787
1548
|
Logger.level = MatterLogLevel.FATAL;
|
|
1788
1549
|
}
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
callbackLogLevel = "debug" /* LogLevel.DEBUG */;
|
|
1550
|
+
let callbackLogLevel = "notice";
|
|
1551
|
+
if (this.matterbridge.getLogLevel() === "info" || Logger.level === MatterLogLevel.INFO)
|
|
1552
|
+
callbackLogLevel = "info";
|
|
1553
|
+
if (this.matterbridge.getLogLevel() === "debug" || Logger.level === MatterLogLevel.DEBUG)
|
|
1554
|
+
callbackLogLevel = "debug";
|
|
1795
1555
|
AnsiLogger.setGlobalCallbackLevel(callbackLogLevel);
|
|
1796
1556
|
this.log.debug(`WebSocketServer logger global callback set to ${callbackLogLevel}`);
|
|
1797
1557
|
await this.matterbridge.nodeContext?.set('matterLogLevel', Logger.level);
|
|
@@ -1843,7 +1603,6 @@ export class Frontend extends EventEmitter {
|
|
|
1843
1603
|
}
|
|
1844
1604
|
break;
|
|
1845
1605
|
case 'setmatterport':
|
|
1846
|
-
// eslint-disable-next-line no-case-declarations
|
|
1847
1606
|
const port = isValidString(data.params.value) ? parseInt(data.params.value) : 0;
|
|
1848
1607
|
if (isValidNumber(port, 5540, 5600)) {
|
|
1849
1608
|
this.log.debug(`Set matter commissioning port to ${CYAN}${port}${db}`);
|
|
@@ -1863,7 +1622,6 @@ export class Frontend extends EventEmitter {
|
|
|
1863
1622
|
}
|
|
1864
1623
|
break;
|
|
1865
1624
|
case 'setmatterdiscriminator':
|
|
1866
|
-
// eslint-disable-next-line no-case-declarations
|
|
1867
1625
|
const discriminator = isValidString(data.params.value) ? parseInt(data.params.value) : 0;
|
|
1868
1626
|
if (isValidNumber(discriminator, 0, 4095)) {
|
|
1869
1627
|
this.log.debug(`Set matter commissioning discriminator to ${CYAN}${discriminator}${db}`);
|
|
@@ -1883,7 +1641,6 @@ export class Frontend extends EventEmitter {
|
|
|
1883
1641
|
}
|
|
1884
1642
|
break;
|
|
1885
1643
|
case 'setmatterpasscode':
|
|
1886
|
-
// eslint-disable-next-line no-case-declarations
|
|
1887
1644
|
const passcode = isValidString(data.params.value) ? parseInt(data.params.value) : 0;
|
|
1888
1645
|
if (isValidNumber(passcode, 1, 99999998) && CommissioningOptions.FORBIDDEN_PASSCODES.includes(passcode) === false) {
|
|
1889
1646
|
this.matterbridge.passcode = passcode;
|
|
@@ -1929,19 +1686,15 @@ export class Frontend extends EventEmitter {
|
|
|
1929
1686
|
return;
|
|
1930
1687
|
}
|
|
1931
1688
|
const config = plugin.configJson;
|
|
1932
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1933
1689
|
const select = plugin.schemaJson?.properties?.blackList?.selectFrom;
|
|
1934
|
-
// this.log.debug(`SelectDevice(selectMode ${select}) data ${debugStringify(data)}`);
|
|
1935
1690
|
if (select === 'serial')
|
|
1936
1691
|
this.log.info(`Selected device serial ${data.params.serial}`);
|
|
1937
1692
|
if (select === 'name')
|
|
1938
1693
|
this.log.info(`Selected device name ${data.params.name}`);
|
|
1939
1694
|
if (config && select && (select === 'serial' || select === 'name')) {
|
|
1940
|
-
// Remove postfix from the serial if it exists
|
|
1941
1695
|
if (config.postfix) {
|
|
1942
1696
|
data.params.serial = data.params.serial.replace('-' + config.postfix, '');
|
|
1943
1697
|
}
|
|
1944
|
-
// Add the serial to the whiteList if the whiteList exists and the serial or name is not already in it
|
|
1945
1698
|
if (isValidArray(config.whiteList, 1)) {
|
|
1946
1699
|
if (select === 'serial' && !config.whiteList.includes(data.params.serial)) {
|
|
1947
1700
|
config.whiteList.push(data.params.serial);
|
|
@@ -1950,7 +1703,6 @@ export class Frontend extends EventEmitter {
|
|
|
1950
1703
|
config.whiteList.push(data.params.name);
|
|
1951
1704
|
}
|
|
1952
1705
|
}
|
|
1953
|
-
// Remove the serial from the blackList if the blackList exists and the serial or name is in it
|
|
1954
1706
|
if (isValidArray(config.blackList, 1)) {
|
|
1955
1707
|
if (select === 'serial' && config.blackList.includes(data.params.serial)) {
|
|
1956
1708
|
config.blackList = config.blackList.filter((item) => item !== localData.params.serial);
|
|
@@ -1978,9 +1730,7 @@ export class Frontend extends EventEmitter {
|
|
|
1978
1730
|
return;
|
|
1979
1731
|
}
|
|
1980
1732
|
const config = plugin.configJson;
|
|
1981
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1982
1733
|
const select = plugin.schemaJson?.properties?.blackList?.selectFrom;
|
|
1983
|
-
// this.log.debug(`UnselectDevice(selectMode ${select}) data ${debugStringify(data)}`);
|
|
1984
1734
|
if (select === 'serial')
|
|
1985
1735
|
this.log.info(`Unselected device serial ${data.params.serial}`);
|
|
1986
1736
|
if (select === 'name')
|
|
@@ -1989,7 +1739,6 @@ export class Frontend extends EventEmitter {
|
|
|
1989
1739
|
if (config.postfix) {
|
|
1990
1740
|
data.params.serial = data.params.serial.replace('-' + config.postfix, '');
|
|
1991
1741
|
}
|
|
1992
|
-
// Remove the serial from the whiteList if the whiteList exists and the serial is in it
|
|
1993
1742
|
if (isValidArray(config.whiteList, 1)) {
|
|
1994
1743
|
if (select === 'serial' && config.whiteList.includes(data.params.serial)) {
|
|
1995
1744
|
config.whiteList = config.whiteList.filter((item) => item !== localData.params.serial);
|
|
@@ -1998,7 +1747,6 @@ export class Frontend extends EventEmitter {
|
|
|
1998
1747
|
config.whiteList = config.whiteList.filter((item) => item !== localData.params.name);
|
|
1999
1748
|
}
|
|
2000
1749
|
}
|
|
2001
|
-
// Add the serial to the blackList
|
|
2002
1750
|
if (isValidArray(config.blackList)) {
|
|
2003
1751
|
if (select === 'serial' && !config.blackList.includes(data.params.serial)) {
|
|
2004
1752
|
config.blackList.push(data.params.serial);
|
|
@@ -2021,7 +1769,6 @@ export class Frontend extends EventEmitter {
|
|
|
2021
1769
|
}
|
|
2022
1770
|
}
|
|
2023
1771
|
else {
|
|
2024
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
2025
1772
|
const localData = data;
|
|
2026
1773
|
this.log.error(`Invalid method from websocket client: ${debugStringify(localData)}`);
|
|
2027
1774
|
sendResponse({ id: localData.id, method: localData.method, src: 'Matterbridge', dst: localData.src, error: 'Invalid method' });
|
|
@@ -2031,46 +1778,23 @@ export class Frontend extends EventEmitter {
|
|
|
2031
1778
|
inspectError(this.log, `Error processing message "${message}" from websocket client`, error);
|
|
2032
1779
|
}
|
|
2033
1780
|
}
|
|
2034
|
-
/**
|
|
2035
|
-
* Sends a WebSocket log message to all connected clients. The function is called by AnsiLogger.setGlobalCallback.
|
|
2036
|
-
*
|
|
2037
|
-
* @param {string} level - The logger level of the message: debug info notice warn error fatal...
|
|
2038
|
-
* @param {string} time - The time string of the message
|
|
2039
|
-
* @param {string} name - The logger name of the message
|
|
2040
|
-
* @param {string} message - The content of the message.
|
|
2041
|
-
*
|
|
2042
|
-
* @remarks
|
|
2043
|
-
* The function removes ANSI escape codes, leading asterisks, non-printable characters, and replaces all occurrences of \t and \n.
|
|
2044
|
-
* It also replaces all occurrences of \" with " and angle-brackets with < and >.
|
|
2045
|
-
* The function sends the message to all connected clients.
|
|
2046
|
-
*/
|
|
2047
1781
|
wssSendLogMessage(level, time, name, message) {
|
|
2048
1782
|
if (!this.listening || this.webSocketServer?.clients.size === 0)
|
|
2049
1783
|
return;
|
|
2050
1784
|
if (!level || !time || !name || !message)
|
|
2051
1785
|
return;
|
|
2052
|
-
// Remove ANSI escape codes from the message
|
|
2053
|
-
// eslint-disable-next-line no-control-regex
|
|
2054
1786
|
message = message.replace(/\x1B\[[0-9;]*[m|s|u|K]/g, '');
|
|
2055
|
-
// Remove leading asterisks from the message
|
|
2056
1787
|
message = message.replace(/^\*+/, '');
|
|
2057
|
-
// Replace all occurrences of \t and \n
|
|
2058
1788
|
message = message.replace(/[\t\n]/g, '');
|
|
2059
|
-
// Remove non-printable characters
|
|
2060
|
-
// eslint-disable-next-line no-control-regex
|
|
2061
1789
|
message = message.replace(/[\x00-\x1F\x7F]/g, '');
|
|
2062
|
-
// Replace all occurrences of \" with "
|
|
2063
1790
|
message = message.replace(/\\"/g, '"');
|
|
2064
|
-
// Define the maximum allowed length for continuous characters without a space
|
|
2065
1791
|
const maxContinuousLength = 100;
|
|
2066
1792
|
const keepStartLength = 20;
|
|
2067
1793
|
const keepEndLength = 20;
|
|
2068
|
-
// Split the message into words
|
|
2069
1794
|
if (level !== 'spawn') {
|
|
2070
1795
|
message = message
|
|
2071
1796
|
.split(' ')
|
|
2072
1797
|
.map((word) => {
|
|
2073
|
-
// If the word length exceeds the max continuous length, insert spaces and truncate
|
|
2074
1798
|
if (word.length > maxContinuousLength) {
|
|
2075
1799
|
return word.slice(0, keepStartLength) + ' ... ' + word.slice(-keepEndLength);
|
|
2076
1800
|
}
|
|
@@ -2078,34 +1802,14 @@ export class Frontend extends EventEmitter {
|
|
|
2078
1802
|
})
|
|
2079
1803
|
.join(' ');
|
|
2080
1804
|
}
|
|
2081
|
-
// Send the message to all connected clients
|
|
2082
1805
|
this.wssBroadcastMessage({ id: 0, src: 'Matterbridge', dst: 'Frontend', method: 'log', success: true, response: { level, time, name, message } });
|
|
2083
1806
|
}
|
|
2084
|
-
/**
|
|
2085
|
-
* Sends a need to refresh WebSocket message to all connected clients.
|
|
2086
|
-
*
|
|
2087
|
-
* @param {string} changed - The changed value.
|
|
2088
|
-
* @param {Record<string, unknown>} params - Additional parameters to send with the message.
|
|
2089
|
-
* possible values for changed:
|
|
2090
|
-
* - 'settings' (when the bridge has started in bridge mode or childbridge mode and when update finds a new version)
|
|
2091
|
-
* - 'plugins'
|
|
2092
|
-
* - 'devices'
|
|
2093
|
-
* - 'matter' with param 'matter' (QRDiv component)
|
|
2094
|
-
* @param {ApiMatter} params.matter - The matter device that has changed. Required if changed is 'matter'.
|
|
2095
|
-
*/
|
|
2096
1807
|
wssSendRefreshRequired(changed, params) {
|
|
2097
1808
|
if (!this.listening || this.webSocketServer?.clients.size === 0)
|
|
2098
1809
|
return;
|
|
2099
1810
|
this.log.debug('Sending a refresh required message to all connected clients');
|
|
2100
|
-
// Send the message to all connected clients
|
|
2101
1811
|
this.wssBroadcastMessage({ id: 0, src: 'Matterbridge', dst: 'Frontend', method: 'refresh_required', success: true, response: { changed, ...params } });
|
|
2102
1812
|
}
|
|
2103
|
-
/**
|
|
2104
|
-
* Sends a need to restart WebSocket message to all connected clients.
|
|
2105
|
-
*
|
|
2106
|
-
* @param {boolean} snackbar - If true, a snackbar message will be sent to all connected clients. Default is true.
|
|
2107
|
-
* @param {boolean} fixed - If true, the restart is fixed and will not be reset by plugin restarts. Default is false.
|
|
2108
|
-
*/
|
|
2109
1813
|
wssSendRestartRequired(snackbar = true, fixed = false) {
|
|
2110
1814
|
if (!this.listening || this.webSocketServer?.clients.size === 0)
|
|
2111
1815
|
return;
|
|
@@ -2114,14 +1818,8 @@ export class Frontend extends EventEmitter {
|
|
|
2114
1818
|
this.matterbridge.fixedRestartRequired = fixed;
|
|
2115
1819
|
if (snackbar === true)
|
|
2116
1820
|
this.wssSendSnackbarMessage(`Restart required`, 0);
|
|
2117
|
-
// Send the message to all connected clients
|
|
2118
1821
|
this.wssBroadcastMessage({ id: 0, src: 'Matterbridge', dst: 'Frontend', method: 'restart_required', success: true, response: { fixed } });
|
|
2119
1822
|
}
|
|
2120
|
-
/**
|
|
2121
|
-
* Sends a no need to restart WebSocket message to all connected clients.
|
|
2122
|
-
*
|
|
2123
|
-
* @param {boolean} snackbar - If true, the snackbar message will be cleared from all connected clients. Default is true.
|
|
2124
|
-
*/
|
|
2125
1823
|
wssSendRestartNotRequired(snackbar = true) {
|
|
2126
1824
|
if (!this.listening || this.webSocketServer?.clients.size === 0)
|
|
2127
1825
|
return;
|
|
@@ -2129,133 +1827,57 @@ export class Frontend extends EventEmitter {
|
|
|
2129
1827
|
this.matterbridge.restartRequired = false;
|
|
2130
1828
|
if (snackbar === true)
|
|
2131
1829
|
this.wssSendCloseSnackbarMessage(`Restart required`);
|
|
2132
|
-
// Send the message to all connected clients
|
|
2133
1830
|
this.wssBroadcastMessage({ id: 0, src: 'Matterbridge', dst: 'Frontend', method: 'restart_not_required', success: true });
|
|
2134
1831
|
}
|
|
2135
|
-
/**
|
|
2136
|
-
* Sends a need to update WebSocket message to all connected clients.
|
|
2137
|
-
*
|
|
2138
|
-
* @param {boolean} devVersion - If true, the update is for a development version. Default is false.
|
|
2139
|
-
*/
|
|
2140
1832
|
wssSendUpdateRequired(devVersion = false) {
|
|
2141
1833
|
if (!this.listening || this.webSocketServer?.clients.size === 0)
|
|
2142
1834
|
return;
|
|
2143
1835
|
this.log.debug('Sending an update required message to all connected clients');
|
|
2144
1836
|
this.matterbridge.updateRequired = true;
|
|
2145
|
-
// Send the message to all connected clients
|
|
2146
1837
|
this.wssBroadcastMessage({ id: 0, src: 'Matterbridge', dst: 'Frontend', method: 'update_required', success: true, response: { devVersion } });
|
|
2147
1838
|
}
|
|
2148
|
-
/**
|
|
2149
|
-
* Sends a cpu update message to all connected clients.
|
|
2150
|
-
*
|
|
2151
|
-
* @param {number} cpuUsage - The CPU usage percentage to send.
|
|
2152
|
-
* @param {number} processCpuUsage - The CPU usage percentage of the process to send.
|
|
2153
|
-
*/
|
|
2154
1839
|
wssSendCpuUpdate(cpuUsage, processCpuUsage) {
|
|
2155
1840
|
if (!this.listening || this.webSocketServer?.clients.size === 0)
|
|
2156
1841
|
return;
|
|
2157
1842
|
if (hasParameter('debug'))
|
|
2158
1843
|
this.log.debug('Sending a cpu update message to all connected clients');
|
|
2159
|
-
// Send the message to all connected clients
|
|
2160
1844
|
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 } });
|
|
2161
1845
|
}
|
|
2162
|
-
/**
|
|
2163
|
-
* Sends a memory update message to all connected clients.
|
|
2164
|
-
*
|
|
2165
|
-
* @param {string} totalMemory - The total memory in bytes.
|
|
2166
|
-
* @param {string} freeMemory - The free memory in bytes.
|
|
2167
|
-
* @param {string} rss - The resident set size in bytes.
|
|
2168
|
-
* @param {string} heapTotal - The total heap memory in bytes.
|
|
2169
|
-
* @param {string} heapUsed - The used heap memory in bytes.
|
|
2170
|
-
* @param {string} external - The external memory in bytes.
|
|
2171
|
-
* @param {string} arrayBuffers - The array buffers memory in bytes.
|
|
2172
|
-
*/
|
|
2173
1846
|
wssSendMemoryUpdate(totalMemory, freeMemory, rss, heapTotal, heapUsed, external, arrayBuffers) {
|
|
2174
1847
|
if (!this.listening || this.webSocketServer?.clients.size === 0)
|
|
2175
1848
|
return;
|
|
2176
1849
|
if (hasParameter('debug'))
|
|
2177
1850
|
this.log.debug('Sending a memory update message to all connected clients');
|
|
2178
|
-
// Send the message to all connected clients
|
|
2179
1851
|
this.wssBroadcastMessage({ id: 0, src: 'Matterbridge', dst: 'Frontend', method: 'memory_update', success: true, response: { totalMemory, freeMemory, rss, heapTotal, heapUsed, external, arrayBuffers } });
|
|
2180
1852
|
}
|
|
2181
|
-
/**
|
|
2182
|
-
* Sends an uptime update message to all connected clients.
|
|
2183
|
-
*
|
|
2184
|
-
* @param {string} systemUptime - The system uptime in a human-readable format.
|
|
2185
|
-
* @param {string} processUptime - The process uptime in a human-readable format.
|
|
2186
|
-
*/
|
|
2187
1853
|
wssSendUptimeUpdate(systemUptime, processUptime) {
|
|
2188
1854
|
if (!this.listening || this.webSocketServer?.clients.size === 0)
|
|
2189
1855
|
return;
|
|
2190
1856
|
if (hasParameter('debug'))
|
|
2191
1857
|
this.log.debug('Sending a uptime update message to all connected clients');
|
|
2192
|
-
// Send the message to all connected clients
|
|
2193
1858
|
this.wssBroadcastMessage({ id: 0, src: 'Matterbridge', dst: 'Frontend', method: 'uptime_update', success: true, response: { systemUptime, processUptime } });
|
|
2194
1859
|
}
|
|
2195
|
-
/**
|
|
2196
|
-
* Sends an open snackbar message to all connected clients.
|
|
2197
|
-
*
|
|
2198
|
-
* @param {string} message - The message to send.
|
|
2199
|
-
* @param {number} timeout - The timeout in seconds for the snackbar message. Default is 5 seconds.
|
|
2200
|
-
* @param {'info' | 'warning' | 'error' | 'success'} severity - The severity of the message.
|
|
2201
|
-
* possible values are: 'info', 'warning', 'error', 'success'. Default is 'info'.
|
|
2202
|
-
*
|
|
2203
|
-
* @remarks
|
|
2204
|
-
* If timeout is 0, the snackbar message will be displayed until closed by the user.
|
|
2205
|
-
*/
|
|
2206
1860
|
wssSendSnackbarMessage(message, timeout = 5, severity = 'info') {
|
|
2207
1861
|
if (!this.listening || this.webSocketServer?.clients.size === 0)
|
|
2208
1862
|
return;
|
|
2209
1863
|
this.log.debug('Sending a snackbar message to all connected clients');
|
|
2210
|
-
// Send the message to all connected clients
|
|
2211
1864
|
this.wssBroadcastMessage({ id: 0, src: 'Matterbridge', dst: 'Frontend', method: 'snackbar', success: true, response: { message, timeout, severity } });
|
|
2212
1865
|
}
|
|
2213
|
-
/**
|
|
2214
|
-
* Sends a close snackbar message to all connected clients.
|
|
2215
|
-
* It will close the snackbar message with the same message and timeout = 0.
|
|
2216
|
-
*
|
|
2217
|
-
* @param {string} message - The message to send.
|
|
2218
|
-
*/
|
|
2219
1866
|
wssSendCloseSnackbarMessage(message) {
|
|
2220
1867
|
if (!this.listening || this.webSocketServer?.clients.size === 0)
|
|
2221
1868
|
return;
|
|
2222
1869
|
this.log.debug('Sending a close snackbar message to all connected clients');
|
|
2223
|
-
// Send the message to all connected clients
|
|
2224
1870
|
this.wssBroadcastMessage({ id: 0, src: 'Matterbridge', dst: 'Frontend', method: 'close_snackbar', success: true, response: { message } });
|
|
2225
1871
|
}
|
|
2226
|
-
/**
|
|
2227
|
-
* Sends an attribute update message to all connected WebSocket clients.
|
|
2228
|
-
*
|
|
2229
|
-
* @param {string | undefined} plugin - The name of the plugin.
|
|
2230
|
-
* @param {string | undefined} serialNumber - The serial number of the device.
|
|
2231
|
-
* @param {string | undefined} uniqueId - The unique identifier of the device.
|
|
2232
|
-
* @param {EndpointNumber} number - The endpoint number where the attribute belongs.
|
|
2233
|
-
* @param {string} id - The endpoint id where the attribute belongs.
|
|
2234
|
-
* @param {string} cluster - The cluster name where the attribute belongs.
|
|
2235
|
-
* @param {string} attribute - The name of the attribute that changed.
|
|
2236
|
-
* @param {number | string | boolean} value - The new value of the attribute.
|
|
2237
|
-
*
|
|
2238
|
-
* @remarks
|
|
2239
|
-
* This method logs a debug message and sends a JSON-formatted message to all connected WebSocket clients
|
|
2240
|
-
* with the updated attribute information.
|
|
2241
|
-
*/
|
|
2242
1872
|
wssSendAttributeChangedMessage(plugin, serialNumber, uniqueId, number, id, cluster, attribute, value) {
|
|
2243
1873
|
if (!this.listening || this.webSocketServer?.clients.size === 0)
|
|
2244
1874
|
return;
|
|
2245
1875
|
this.log.debug('Sending an attribute update message to all connected clients');
|
|
2246
|
-
// Send the message to all connected clients
|
|
2247
1876
|
this.wssBroadcastMessage({ id: 0, src: 'Matterbridge', dst: 'Frontend', method: 'state_update', success: true, response: { plugin, serialNumber, uniqueId, number, id, cluster, attribute, value } });
|
|
2248
1877
|
}
|
|
2249
|
-
/**
|
|
2250
|
-
* Sends a message to all connected clients.
|
|
2251
|
-
* This is an helper function to send a broadcast message to all connected clients.
|
|
2252
|
-
*
|
|
2253
|
-
* @param {WsMessageBroadcast} msg - The message to send.
|
|
2254
|
-
*/
|
|
2255
1878
|
wssBroadcastMessage(msg) {
|
|
2256
1879
|
if (!this.listening || this.webSocketServer?.clients.size === 0)
|
|
2257
1880
|
return;
|
|
2258
|
-
// Send the message to all connected clients
|
|
2259
1881
|
const stringifiedMsg = JSON.stringify(msg);
|
|
2260
1882
|
if (msg.method !== 'log')
|
|
2261
1883
|
this.log.debug(`Sending a broadcast message: ${debugStringify(msg)}`);
|
|
@@ -2266,4 +1888,3 @@ export class Frontend extends EventEmitter {
|
|
|
2266
1888
|
});
|
|
2267
1889
|
}
|
|
2268
1890
|
}
|
|
2269
|
-
//# sourceMappingURL=frontend.js.map
|