matterbridge 3.3.1-dev-20251009-edb969d → 3.3.1-dev-20251011-c8b30f8

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/dist/cli.js CHANGED
@@ -3,7 +3,7 @@ if (process.argv.includes('--loader') || process.argv.includes('-loader'))
3
3
  import os from 'node:os';
4
4
  import { inspect } from 'node:util';
5
5
  import { AnsiLogger, BRIGHT, CYAN, db, RED, YELLOW } from 'node-ansi-logger';
6
- import { cliEmitter, setLastCpuUsage, setLastProcessCpuUsage } from './cliEmitter.js';
6
+ import { cliEmitter, setLastOsCpuUsage, setLastProcessCpuUsage } from './cliEmitter.js';
7
7
  import { history, historyIndex, historySize, setHistoryIndex } from './cliHistory.js';
8
8
  import { getIntParameter, hasParameter } from './utils/commandLine.js';
9
9
  import { Matterbridge } from './matterbridge.js';
@@ -21,6 +21,8 @@ let peakProcessCpu = 0;
21
21
  let peakRss = 0;
22
22
  let peakHeapUsed = 0;
23
23
  let peakHeapTotal = 0;
24
+ let peakExternal = 0;
25
+ let peakArrayBuffers = 0;
24
26
  const log = new AnsiLogger({ logName: 'Cli', logTimestampFormat: 4, logLevel: hasParameter('debug') ? "debug" : "info" });
25
27
  const formatCpuUsage = (percent) => {
26
28
  return `${percent.toFixed(2).padStart(5, ' ')} %`;
@@ -60,7 +62,7 @@ async function startCpuMemoryCheck() {
60
62
  const systemUptime = formatOsUpTime(Math.floor(os.uptime()));
61
63
  const processUptime = formatOsUpTime(Math.floor(process.uptime()));
62
64
  cliEmitter.emit('uptime', systemUptime, processUptime);
63
- const totalMememory = formatMemoryUsage(os.totalmem());
65
+ const totalMemory = formatMemoryUsage(os.totalmem());
64
66
  const freeMemory = formatMemoryUsage(os.freemem());
65
67
  const memoryUsageRaw = process.memoryUsage();
66
68
  const rss = formatMemoryUsage(memoryUsageRaw.rss);
@@ -83,7 +85,17 @@ async function startCpuMemoryCheck() {
83
85
  log.debug(`****${RED}${BRIGHT}HeapTotal peak detected.${db} Peak heapTotal from ${CYAN}${formatMemoryUsage(peakHeapTotal)}${db} to ${CYAN}${formatMemoryUsage(memoryUsageRaw.heapTotal)}${db}`);
84
86
  peakHeapTotal = memoryUsageRaw.heapTotal;
85
87
  }
86
- cliEmitter.emit('memory', totalMememory, freeMemory, rss, heapTotal, heapUsed, external, arrayBuffers);
88
+ if (memoryUsageRaw.external > peakExternal) {
89
+ if (peakExternal && trace)
90
+ log.debug(`****${RED}${BRIGHT}External peak detected.${db} Peak external from ${CYAN}${formatMemoryUsage(peakExternal)}${db} to ${CYAN}${formatMemoryUsage(memoryUsageRaw.external)}${db}`);
91
+ peakExternal = memoryUsageRaw.external;
92
+ }
93
+ if (memoryUsageRaw.arrayBuffers > peakArrayBuffers) {
94
+ if (peakArrayBuffers && trace)
95
+ log.debug(`****${RED}${BRIGHT}ArrayBuffers peak detected.${db} Peak arrayBuffers from ${CYAN}${formatMemoryUsage(peakArrayBuffers)}${db} to ${CYAN}${formatMemoryUsage(memoryUsageRaw.arrayBuffers)}${db}`);
96
+ peakArrayBuffers = memoryUsageRaw.arrayBuffers;
97
+ }
98
+ cliEmitter.emit('memory', totalMemory, freeMemory, rss, heapTotal, heapUsed, external, arrayBuffers);
87
99
  const currCpus = os.cpus();
88
100
  if (currCpus.length !== prevCpus.length) {
89
101
  prevCpus = currCpus;
@@ -98,16 +110,16 @@ async function startCpuMemoryCheck() {
98
110
  totalIdle += idleDiff;
99
111
  totalTick += totalDiff;
100
112
  });
101
- const cpuUsage = 100 - (totalIdle / totalTick) * 100;
102
- if (totalTick === 0 || isNaN(cpuUsage) || !isFinite(cpuUsage) || cpuUsage <= 0) {
113
+ const osCpuUsage = 100 - (totalIdle / totalTick) * 100;
114
+ if (totalTick === 0 || isNaN(osCpuUsage) || !isFinite(osCpuUsage) || osCpuUsage <= 0) {
103
115
  log.debug(`Cpu check failed, using previous cpus`);
104
116
  }
105
117
  else {
106
- setLastCpuUsage(cpuUsage);
107
- if (cpuUsage > peakCpu) {
108
- peakCpu = cpuUsage;
118
+ setLastOsCpuUsage(osCpuUsage);
119
+ if (osCpuUsage > peakCpu) {
120
+ peakCpu = osCpuUsage;
109
121
  if (peakCpu && trace)
110
- log.debug(`****${RED}${BRIGHT}Cpu peak detected.${db} Peak cpu from ${CYAN}${formatCpuUsage(peakCpu)}${db} to ${CYAN}${formatCpuUsage(cpuUsage)}${db}`);
122
+ log.debug(`****${RED}${BRIGHT}Cpu peak detected.${db} Peak cpu from ${CYAN}${formatCpuUsage(peakCpu)}${db} to ${CYAN}${formatCpuUsage(osCpuUsage)}${db}`);
111
123
  }
112
124
  }
113
125
  prevCpus = currCpus;
@@ -115,7 +127,7 @@ async function startCpuMemoryCheck() {
115
127
  const userMs = diff.user / 1000;
116
128
  const systemMs = diff.system / 1000;
117
129
  const totalMs = userMs + systemMs;
118
- const processCpuUsage = Number(((totalMs / memoryCheckIntervalMs) * 100).toFixed(2));
130
+ const processCpuUsage = Number((((totalMs / memoryCheckIntervalMs) * 100) / currCpus.length).toFixed(2));
119
131
  if (processCpuUsage > peakProcessCpu) {
120
132
  peakProcessCpu = processCpuUsage;
121
133
  if (peakProcessCpu && trace)
@@ -123,9 +135,10 @@ async function startCpuMemoryCheck() {
123
135
  }
124
136
  prevProcessCpu = process.cpuUsage();
125
137
  setLastProcessCpuUsage(processCpuUsage);
126
- cliEmitter.emit('cpu', cpuUsage, processCpuUsage);
138
+ cliEmitter.emit('cpu', osCpuUsage, processCpuUsage);
127
139
  const entry = history[historyIndex];
128
- entry.cpu = cpuUsage;
140
+ entry.timestamp = Date.now();
141
+ entry.cpu = osCpuUsage;
129
142
  entry.peakCpu = peakCpu;
130
143
  entry.processCpu = processCpuUsage;
131
144
  entry.peakProcessCpu = peakProcessCpu;
@@ -135,16 +148,25 @@ async function startCpuMemoryCheck() {
135
148
  entry.peakHeapUsed = peakHeapUsed;
136
149
  entry.heapTotal = memoryUsageRaw.heapTotal;
137
150
  entry.peakHeapTotal = peakHeapTotal;
138
- entry.timestamp = Date.now();
139
151
  setHistoryIndex((historyIndex + 1) % historySize);
140
152
  if (trace)
141
- log.debug(`***${YELLOW}${BRIGHT}Host cpu:${db} ${CYAN}${formatCpuUsage(cpuUsage)}${db} (peak ${formatCpuUsage(peakCpu)}) ${YELLOW}${BRIGHT}Process cpu:${db} ${CYAN}${formatCpuUsage(processCpuUsage)}${db} (peak ${formatCpuUsage(peakProcessCpu)}) ${YELLOW}${BRIGHT}Process memory:${db} rss ${CYAN}${rss}${db} (peak ${formatMemoryUsage(peakRss)}) heapUsed ${CYAN}${heapUsed}${db} (peak ${formatMemoryUsage(peakHeapUsed)}) heapTotal ${CYAN}${heapTotal}${db} (peak ${formatMemoryUsage(peakHeapTotal)}) external ${external} arrayBuffers ${arrayBuffers}`);
153
+ log.debug(`***${YELLOW}${BRIGHT}Host cpu:${db} ` +
154
+ `${CYAN}${formatCpuUsage(osCpuUsage)}${db} (peak ${formatCpuUsage(peakCpu)}) ` +
155
+ `${YELLOW}${BRIGHT}Process cpu:${db} ` +
156
+ `${CYAN}${formatCpuUsage(processCpuUsage)}${db} (peak ${formatCpuUsage(peakProcessCpu)}) ` +
157
+ `${YELLOW}${BRIGHT}Process memory:${db} ` +
158
+ `rss ${CYAN}${rss}${db} (peak ${formatMemoryUsage(peakRss)}) ` +
159
+ `heapUsed ${CYAN}${heapUsed}${db} (peak ${formatMemoryUsage(peakHeapUsed)}) ` +
160
+ `heapTotal ${CYAN}${heapTotal}${db} (peak ${formatMemoryUsage(peakHeapTotal)}) ` +
161
+ `external ${CYAN}${external}${db} (peak ${formatMemoryUsage(peakExternal)}) ` +
162
+ `arrayBuffers ${CYAN}${arrayBuffers}${db} (peak ${formatMemoryUsage(peakArrayBuffers)})`);
142
163
  };
143
164
  clearInterval(memoryCheckInterval);
144
165
  memoryCheckInterval = setInterval(interval, memoryCheckIntervalMs).unref();
145
166
  clearTimeout(memoryPeakResetTimeout);
146
167
  memoryPeakResetTimeout = setTimeout(() => {
147
- log.debug(`****${RED}${BRIGHT}Cpu and memory peaks reset after first 5 minutes.${db}`);
168
+ if (trace)
169
+ log.debug(`****${RED}${BRIGHT}Cpu and memory peaks reset after first 5 minutes.${db}`);
148
170
  peakCpu = 0;
149
171
  peakProcessCpu = 0;
150
172
  peakRss = 0;
@@ -154,7 +176,13 @@ async function startCpuMemoryCheck() {
154
176
  }
155
177
  async function stopCpuMemoryCheck() {
156
178
  if (trace) {
157
- log.debug(`***Cpu memory check stopped. Peak cpu: ${CYAN}${peakCpu.toFixed(2)} %${db}. Peak rss: ${CYAN}${formatMemoryUsage(peakRss)}${db}. Peak heapUsed: ${CYAN}${formatMemoryUsage(peakHeapUsed)}${db}. Peak heapTotal: ${CYAN}${formatMemoryUsage(peakHeapTotal)}${db}`);
179
+ log.debug(`***Cpu memory check stopped. ` +
180
+ `Peak cpu: ${CYAN}${peakCpu.toFixed(2)} %${db}. ` +
181
+ `Peak rss: ${CYAN}${formatMemoryUsage(peakRss)}${db}. ` +
182
+ `Peak heapUsed: ${CYAN}${formatMemoryUsage(peakHeapUsed)}${db}. ` +
183
+ `Peak heapTotal: ${CYAN}${formatMemoryUsage(peakHeapTotal)}${db}. ` +
184
+ `Peak external: ${CYAN}${formatMemoryUsage(peakExternal)}${db}. ` +
185
+ `Peak arrayBuffers: ${CYAN}${formatMemoryUsage(peakArrayBuffers)}${db}.`);
158
186
  }
159
187
  clearInterval(memoryCheckInterval);
160
188
  clearTimeout(memoryPeakResetTimeout);
@@ -2,10 +2,10 @@ if (process.argv.includes('--loader') || process.argv.includes('-loader'))
2
2
  console.log('\u001B[32mCli emitter loaded.\u001B[40;0m');
3
3
  import { EventEmitter } from 'node:events';
4
4
  export const cliEmitter = new EventEmitter();
5
- export let lastCpuUsage = 0;
5
+ export let lastOsCpuUsage = 0;
6
6
  export let lastProcessCpuUsage = 0;
7
- export function setLastCpuUsage(val) {
8
- lastCpuUsage = val;
7
+ export function setLastOsCpuUsage(val) {
8
+ lastOsCpuUsage = val;
9
9
  }
10
10
  export function setLastProcessCpuUsage(val) {
11
11
  lastProcessCpuUsage = val;
@@ -14,6 +14,7 @@ export function setHistoryIndex(index) {
14
14
  historyIndex = index;
15
15
  }
16
16
  export const history = Array.from({ length: historySize }, () => ({
17
+ timestamp: 0,
17
18
  cpu: 0,
18
19
  peakCpu: 0,
19
20
  processCpu: 0,
@@ -24,7 +25,10 @@ export const history = Array.from({ length: historySize }, () => ({
24
25
  peakHeapUsed: 0,
25
26
  heapTotal: 0,
26
27
  peakHeapTotal: 0,
27
- timestamp: 0,
28
+ external: 0,
29
+ peakExternal: 0,
30
+ arrayBuffers: 0,
31
+ peakArrayBuffers: 0,
28
32
  }));
29
33
  export function generateHistoryPage(options = {}) {
30
34
  const pageTitle = options.pageTitle ?? 'Matterbridge CPU & Memory History';
package/dist/frontend.js CHANGED
@@ -3,20 +3,21 @@ if (process.argv.includes('--loader') || process.argv.includes('-loader'))
3
3
  import os from 'node:os';
4
4
  import path from 'node:path';
5
5
  import EventEmitter from 'node:events';
6
- import express from 'express';
7
- import WebSocket, { WebSocketServer } from 'ws';
8
- import multer from 'multer';
9
6
  import { AnsiLogger, stringify, debugStringify, CYAN, db, er, nf, rs, UNDERLINE, UNDERLINEOFF, YELLOW, nt, wr } from 'node-ansi-logger';
10
7
  import { Logger, LogLevel as MatterLogLevel, LogFormat as MatterLogFormat, Lifecycle, LogDestination, Diagnostic, Time, FabricIndex } from '@matter/main';
11
8
  import { BridgedDeviceBasicInformation } from '@matter/main/clusters/bridged-device-basic-information';
12
9
  import { PowerSource } from '@matter/main/clusters/power-source';
13
10
  import { DeviceAdvertiser, DeviceCommissioner, FabricManager } from '@matter/main/protocol';
14
11
  import { CommissioningOptions } from '@matter/main/types';
15
- import { MATTER_LOGGER_FILE, MATTER_STORAGE_NAME, MATTERBRIDGE_LOGGER_FILE, NODE_STORAGE_DIR, plg } from './matterbridgeTypes.js';
16
- import { createZip, isValidArray, isValidNumber, isValidObject, isValidString, isValidBoolean, withTimeout, hasParameter, wait, inspectError } from './utils/export.js';
12
+ import { MATTER_LOGGER_FILE, MATTER_STORAGE_NAME, MATTERBRIDGE_DIAGNOSTIC_FILE, MATTERBRIDGE_HISTORY_FILE, MATTERBRIDGE_LOGGER_FILE, NODE_STORAGE_DIR, plg } from './matterbridgeTypes.js';
13
+ import { isValidArray, isValidNumber, isValidObject, isValidString, isValidBoolean } from './utils/isvalid.js';
14
+ import { createZip } from './utils/createZip.js';
15
+ import { hasParameter } from './utils/commandLine.js';
16
+ import { withTimeout, wait } from './utils/wait.js';
17
+ import { inspectError } from './utils/error.js';
17
18
  import { formatMemoryUsage, formatOsUpTime } from './utils/network.js';
18
19
  import { capitalizeFirstLetter, getAttribute } from './matterbridgeEndpointHelpers.js';
19
- import { cliEmitter, lastCpuUsage, lastProcessCpuUsage } from './cliEmitter.js';
20
+ import { cliEmitter, lastOsCpuUsage, lastProcessCpuUsage } from './cliEmitter.js';
20
21
  import { generateHistoryPage } from './cliHistory.js';
21
22
  import { BroadcastServer } from './broadcastServer.js';
22
23
  export class Frontend extends EventEmitter {
@@ -94,9 +95,11 @@ export class Frontend extends EventEmitter {
94
95
  async start(port = 8283) {
95
96
  this.port = port;
96
97
  this.log.debug(`Initializing the frontend ${hasParameter('ssl') ? 'https' : 'http'} server on port ${YELLOW}${this.port}${db}`);
98
+ const multer = await import('multer');
97
99
  const uploadDir = path.join(this.matterbridge.matterbridgeDirectory, 'uploads');
98
- const upload = multer({ dest: uploadDir });
99
- this.expressApp = express();
100
+ const upload = multer.default({ dest: uploadDir });
101
+ const express = await import('express');
102
+ this.expressApp = express.default();
100
103
  this.expressApp.use(express.static(path.join(this.matterbridge.rootDirectory, 'frontend/build')));
101
104
  if (!hasParameter('ssl')) {
102
105
  const http = await import('node:http');
@@ -245,8 +248,9 @@ export class Frontend extends EventEmitter {
245
248
  return;
246
249
  });
247
250
  }
251
+ const ws = await import('ws');
248
252
  this.log.debug(`Creating WebSocketServer...`);
249
- this.webSocketServer = new WebSocketServer(hasParameter('ssl') ? { server: this.httpsServer } : { server: this.httpServer });
253
+ this.webSocketServer = new ws.WebSocketServer(hasParameter('ssl') ? { server: this.httpsServer } : { server: this.httpServer });
250
254
  this.webSocketServer.on('connection', (ws, request) => {
251
255
  const clientIp = request.socket.remoteAddress;
252
256
  let callbackLogLevel = "notice";
@@ -419,11 +423,11 @@ export class Frontend extends EventEmitter {
419
423
  serverNodes.push(device.serverNode);
420
424
  }
421
425
  const fs = await import('node:fs');
422
- if (fs.existsSync(path.join(this.matterbridge.matterbridgeDirectory, 'diagnostic.log')))
423
- fs.unlinkSync(path.join(this.matterbridge.matterbridgeDirectory, 'diagnostic.log'));
426
+ if (fs.existsSync(path.join(this.matterbridge.matterbridgeDirectory, MATTERBRIDGE_DIAGNOSTIC_FILE)))
427
+ fs.unlinkSync(path.join(this.matterbridge.matterbridgeDirectory, MATTERBRIDGE_DIAGNOSTIC_FILE));
424
428
  const diagnosticDestination = LogDestination({ name: 'diagnostic', level: MatterLogLevel.INFO, format: MatterLogFormat.formats.plain });
425
429
  diagnosticDestination.write = async (text, _message) => {
426
- await fs.promises.appendFile(path.join(this.matterbridge.matterbridgeDirectory, 'diagnostic.log'), text + '\n', { encoding: 'utf8' });
430
+ await fs.promises.appendFile(path.join(this.matterbridge.matterbridgeDirectory, MATTERBRIDGE_DIAGNOSTIC_FILE), text + '\n', { encoding: 'utf8' });
427
431
  };
428
432
  Logger.destinations.diagnostic = diagnosticDestination;
429
433
  if (!diagnosticDestination.context) {
@@ -440,15 +444,28 @@ export class Frontend extends EventEmitter {
440
444
  await wait(500);
441
445
  try {
442
446
  const fs = await import('node:fs');
443
- const data = await fs.promises.readFile(path.join(this.matterbridge.matterbridgeDirectory, 'diagnostic.log'), 'utf8');
447
+ const data = await fs.promises.readFile(path.join(this.matterbridge.matterbridgeDirectory, MATTERBRIDGE_DIAGNOSTIC_FILE), 'utf8');
444
448
  res.type('text/plain');
445
449
  res.send(data.slice(29));
446
450
  }
447
451
  catch (error) {
448
- this.log.error(`Error reading diagnostic log file ${MATTER_LOGGER_FILE}: ${error instanceof Error ? error.message : error}`);
452
+ this.log.error(`Error reading diagnostic log file ${MATTERBRIDGE_DIAGNOSTIC_FILE}: ${error instanceof Error ? error.message : error}`);
449
453
  res.status(500).send('Error reading diagnostic log file.');
450
454
  }
451
455
  });
456
+ this.expressApp.get('/api/viewhistory', async (req, res) => {
457
+ this.log.debug('The frontend sent /api/viewhistory');
458
+ try {
459
+ const fs = await import('node:fs');
460
+ const data = await fs.promises.readFile(path.join(this.matterbridge.matterbridgeDirectory, MATTERBRIDGE_HISTORY_FILE), 'utf8');
461
+ res.type('text/html');
462
+ res.send(data);
463
+ }
464
+ catch (error) {
465
+ this.log.error(`Error reading history log file ${MATTERBRIDGE_HISTORY_FILE}: ${error instanceof Error ? error.message : error}`);
466
+ res.status(500).send('Error reading history log file. Please create the history log before loading it.');
467
+ }
468
+ });
452
469
  this.expressApp.get('/api/shellyviewsystemlog', async (req, res) => {
453
470
  this.log.debug('The frontend sent /api/shellyviewsystemlog');
454
471
  try {
@@ -612,6 +629,7 @@ export class Frontend extends EventEmitter {
612
629
  }
613
630
  async stop() {
614
631
  this.log.debug('Stopping the frontend...');
632
+ const ws = await import('ws');
615
633
  if (this.expressApp) {
616
634
  this.expressApp.removeAllListeners();
617
635
  this.expressApp = undefined;
@@ -620,7 +638,7 @@ export class Frontend extends EventEmitter {
620
638
  if (this.webSocketServer) {
621
639
  this.log.debug('Closing WebSocket server...');
622
640
  this.webSocketServer.clients.forEach((client) => {
623
- if (client.readyState === WebSocket.OPEN) {
641
+ if (client.readyState === ws.WebSocket.OPEN) {
624
642
  client.close();
625
643
  }
626
644
  });
@@ -666,7 +684,7 @@ export class Frontend extends EventEmitter {
666
684
  this.matterbridge.systemInformation.freeMemory = formatMemoryUsage(os.freemem());
667
685
  this.matterbridge.systemInformation.systemUptime = formatOsUpTime(os.uptime());
668
686
  this.matterbridge.systemInformation.processUptime = formatOsUpTime(Math.floor(process.uptime()));
669
- this.matterbridge.systemInformation.cpuUsage = lastCpuUsage.toFixed(2) + ' %';
687
+ this.matterbridge.systemInformation.cpuUsage = lastOsCpuUsage.toFixed(2) + ' %';
670
688
  this.matterbridge.systemInformation.processCpuUsage = lastProcessCpuUsage.toFixed(2) + ' %';
671
689
  this.matterbridge.systemInformation.rss = formatMemoryUsage(process.memoryUsage().rss);
672
690
  this.matterbridge.systemInformation.heapTotal = formatMemoryUsage(process.memoryUsage().heapTotal);
@@ -986,7 +1004,7 @@ export class Frontend extends EventEmitter {
986
1004
  async wsMessageHandler(client, message) {
987
1005
  let data;
988
1006
  const sendResponse = (data) => {
989
- if (client.readyState === WebSocket.OPEN) {
1007
+ if (client.readyState === client.OPEN) {
990
1008
  if ('response' in data) {
991
1009
  const { response, ...rest } = data;
992
1010
  this.log.debug(`Sending api response message: ${debugStringify(rest)}`);
@@ -1271,7 +1289,7 @@ export class Frontend extends EventEmitter {
1271
1289
  sendResponse({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, success: true });
1272
1290
  }
1273
1291
  else if (data.method === '/api/generatehistorypage') {
1274
- generateHistoryPage({ outputPath: path.join(this.matterbridge.rootDirectory, 'frontend/build', 'history.html'), pageTitle: `Matterbridge on ${this.matterbridge.systemInformation.hostname} Cpu & Memory History` });
1292
+ generateHistoryPage({ outputPath: path.join(this.matterbridge.matterbridgeDirectory, MATTERBRIDGE_HISTORY_FILE), pageTitle: `Matterbridge on ${this.matterbridge.systemInformation.hostname} Cpu & Memory History` });
1275
1293
  sendResponse({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, success: true });
1276
1294
  }
1277
1295
  else if (data.method === '/api/matter') {
@@ -1708,6 +1726,8 @@ export class Frontend extends EventEmitter {
1708
1726
  }
1709
1727
  }
1710
1728
  wssSendLogMessage(level, time, name, message) {
1729
+ if (!this.listening || this.webSocketServer?.clients.size === 0)
1730
+ return;
1711
1731
  if (!level || !time || !name || !message)
1712
1732
  return;
1713
1733
  message = message.replace(/\x1B\[[0-9;]*[m|s|u|K]/g, '');
@@ -1732,10 +1752,14 @@ export class Frontend extends EventEmitter {
1732
1752
  this.wssBroadcastMessage({ id: 0, src: 'Matterbridge', dst: 'Frontend', method: 'log', success: true, response: { level, time, name, message } });
1733
1753
  }
1734
1754
  wssSendRefreshRequired(changed, params) {
1755
+ if (!this.listening || this.webSocketServer?.clients.size === 0)
1756
+ return;
1735
1757
  this.log.debug('Sending a refresh required message to all connected clients');
1736
1758
  this.wssBroadcastMessage({ id: 0, src: 'Matterbridge', dst: 'Frontend', method: 'refresh_required', success: true, response: { changed, ...params } });
1737
1759
  }
1738
1760
  wssSendRestartRequired(snackbar = true, fixed = false) {
1761
+ if (!this.listening || this.webSocketServer?.clients.size === 0)
1762
+ return;
1739
1763
  this.log.debug('Sending a restart required message to all connected clients');
1740
1764
  this.matterbridge.restartRequired = true;
1741
1765
  this.matterbridge.fixedRestartRequired = fixed;
@@ -1744,6 +1768,8 @@ export class Frontend extends EventEmitter {
1744
1768
  this.wssBroadcastMessage({ id: 0, src: 'Matterbridge', dst: 'Frontend', method: 'restart_required', success: true, response: { fixed } });
1745
1769
  }
1746
1770
  wssSendRestartNotRequired(snackbar = true) {
1771
+ if (!this.listening || this.webSocketServer?.clients.size === 0)
1772
+ return;
1747
1773
  this.log.debug('Sending a restart not required message to all connected clients');
1748
1774
  this.matterbridge.restartRequired = false;
1749
1775
  if (snackbar === true)
@@ -1751,43 +1777,59 @@ export class Frontend extends EventEmitter {
1751
1777
  this.wssBroadcastMessage({ id: 0, src: 'Matterbridge', dst: 'Frontend', method: 'restart_not_required', success: true });
1752
1778
  }
1753
1779
  wssSendUpdateRequired(devVersion = false) {
1780
+ if (!this.listening || this.webSocketServer?.clients.size === 0)
1781
+ return;
1754
1782
  this.log.debug('Sending an update required message to all connected clients');
1755
1783
  this.matterbridge.updateRequired = true;
1756
1784
  this.wssBroadcastMessage({ id: 0, src: 'Matterbridge', dst: 'Frontend', method: 'update_required', success: true, response: { devVersion } });
1757
1785
  }
1758
1786
  wssSendCpuUpdate(cpuUsage, processCpuUsage) {
1787
+ if (!this.listening || this.webSocketServer?.clients.size === 0)
1788
+ return;
1759
1789
  if (hasParameter('debug'))
1760
1790
  this.log.debug('Sending a cpu update message to all connected clients');
1761
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 } });
1762
1792
  }
1763
1793
  wssSendMemoryUpdate(totalMemory, freeMemory, rss, heapTotal, heapUsed, external, arrayBuffers) {
1794
+ if (!this.listening || this.webSocketServer?.clients.size === 0)
1795
+ return;
1764
1796
  if (hasParameter('debug'))
1765
1797
  this.log.debug('Sending a memory update message to all connected clients');
1766
1798
  this.wssBroadcastMessage({ id: 0, src: 'Matterbridge', dst: 'Frontend', method: 'memory_update', success: true, response: { totalMemory, freeMemory, rss, heapTotal, heapUsed, external, arrayBuffers } });
1767
1799
  }
1768
1800
  wssSendUptimeUpdate(systemUptime, processUptime) {
1801
+ if (!this.listening || this.webSocketServer?.clients.size === 0)
1802
+ return;
1769
1803
  if (hasParameter('debug'))
1770
1804
  this.log.debug('Sending a uptime update message to all connected clients');
1771
1805
  this.wssBroadcastMessage({ id: 0, src: 'Matterbridge', dst: 'Frontend', method: 'uptime_update', success: true, response: { systemUptime, processUptime } });
1772
1806
  }
1773
1807
  wssSendSnackbarMessage(message, timeout = 5, severity = 'info') {
1808
+ if (!this.listening || this.webSocketServer?.clients.size === 0)
1809
+ return;
1774
1810
  this.log.debug('Sending a snackbar message to all connected clients');
1775
1811
  this.wssBroadcastMessage({ id: 0, src: 'Matterbridge', dst: 'Frontend', method: 'snackbar', success: true, response: { message, timeout, severity } });
1776
1812
  }
1777
1813
  wssSendCloseSnackbarMessage(message) {
1814
+ if (!this.listening || this.webSocketServer?.clients.size === 0)
1815
+ return;
1778
1816
  this.log.debug('Sending a close snackbar message to all connected clients');
1779
1817
  this.wssBroadcastMessage({ id: 0, src: 'Matterbridge', dst: 'Frontend', method: 'close_snackbar', success: true, response: { message } });
1780
1818
  }
1781
1819
  wssSendAttributeChangedMessage(plugin, serialNumber, uniqueId, number, id, cluster, attribute, value) {
1820
+ if (!this.listening || this.webSocketServer?.clients.size === 0)
1821
+ return;
1782
1822
  this.log.debug('Sending an attribute update message to all connected clients');
1783
1823
  this.wssBroadcastMessage({ id: 0, src: 'Matterbridge', dst: 'Frontend', method: 'state_update', success: true, response: { plugin, serialNumber, uniqueId, number, id, cluster, attribute, value } });
1784
1824
  }
1785
1825
  wssBroadcastMessage(msg) {
1826
+ if (!this.listening || this.webSocketServer?.clients.size === 0)
1827
+ return;
1786
1828
  const stringifiedMsg = JSON.stringify(msg);
1787
1829
  if (msg.method !== 'log')
1788
1830
  this.log.debug(`Sending a broadcast message: ${debugStringify(msg)}`);
1789
1831
  this.webSocketServer?.clients.forEach((client) => {
1790
- if (client.readyState === WebSocket.OPEN) {
1832
+ if (client.readyState === client.OPEN) {
1791
1833
  client.send(stringifiedMsg);
1792
1834
  }
1793
1835
  });
@@ -871,26 +871,23 @@ export class Matterbridge extends EventEmitter {
871
871
  this.log.debug(`Command Line Arguments: ${cmdArgs}`);
872
872
  }
873
873
  async setLogLevel(logLevel) {
874
- if (this.log)
875
- this.log.logLevel = logLevel;
874
+ this.log.logLevel = logLevel;
876
875
  this.frontend.logLevel = logLevel;
877
876
  MatterbridgeEndpoint.logLevel = logLevel;
878
- if (this.devices)
879
- this.devices.logLevel = logLevel;
880
- if (this.plugins)
881
- this.plugins.logLevel = logLevel;
877
+ this.devices.logLevel = logLevel;
878
+ this.plugins.logLevel = logLevel;
882
879
  for (const plugin of this.plugins) {
883
880
  if (!plugin.platform || !plugin.platform.log || !plugin.platform.config)
884
881
  continue;
885
- plugin.platform.log.logLevel = plugin.platform.config.debug === true ? "debug" : this.log.logLevel;
886
- await plugin.platform.onChangeLoggerLevel(plugin.platform.config.debug === true ? "debug" : this.log.logLevel);
882
+ plugin.platform.log.logLevel = plugin.platform.config.debug === true ? "debug" : logLevel;
883
+ await plugin.platform.onChangeLoggerLevel(plugin.platform.config.debug === true ? "debug" : logLevel);
887
884
  }
888
885
  let callbackLogLevel = "notice";
889
- if (this.log.logLevel === "info" || Logger.level === MatterLogLevel.INFO)
886
+ if (logLevel === "info" || Logger.level === MatterLogLevel.INFO)
890
887
  callbackLogLevel = "info";
891
- if (this.log.logLevel === "debug" || Logger.level === MatterLogLevel.DEBUG)
888
+ if (logLevel === "debug" || Logger.level === MatterLogLevel.DEBUG)
892
889
  callbackLogLevel = "debug";
893
- AnsiLogger.setGlobalCallback(this.frontend.wssSendLogMessage.bind(this.frontend), callbackLogLevel);
890
+ AnsiLogger.setGlobalCallbackLevel(callbackLogLevel);
894
891
  this.log.debug(`WebSocketServer logger global callback set to ${callbackLogLevel}`);
895
892
  }
896
893
  getLogLevel() {
@@ -5,3 +5,5 @@ export const MATTERBRIDGE_LOGGER_FILE = 'matterbridge.log';
5
5
  export const MATTER_LOGGER_FILE = 'matter.log';
6
6
  export const NODE_STORAGE_DIR = 'storage';
7
7
  export const MATTER_STORAGE_NAME = 'matterstorage';
8
+ export const MATTERBRIDGE_DIAGNOSTIC_FILE = 'diagnostic.log';
9
+ export const MATTERBRIDGE_HISTORY_FILE = 'history.html';