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