matterbridge 3.1.2-dev-20250705-7da1eac → 3.1.2-dev-20250706-6c6481e
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 +2 -0
- package/dist/frontend.js +34 -54
- package/dist/matterbridge.js +2 -2
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
package/dist/frontend.js
CHANGED
|
@@ -7,12 +7,12 @@ import EventEmitter from 'node:events';
|
|
|
7
7
|
import express from 'express';
|
|
8
8
|
import WebSocket, { WebSocketServer } from 'ws';
|
|
9
9
|
import multer from 'multer';
|
|
10
|
-
import { AnsiLogger, stringify, debugStringify, CYAN, db, er, nf, rs, UNDERLINE, UNDERLINEOFF,
|
|
10
|
+
import { AnsiLogger, stringify, debugStringify, CYAN, db, er, nf, rs, UNDERLINE, UNDERLINEOFF, YELLOW, nt } from 'node-ansi-logger';
|
|
11
11
|
import { Logger, LogLevel as MatterLogLevel, LogFormat as MatterLogFormat, Lifecycle } from '@matter/main';
|
|
12
12
|
import { BridgedDeviceBasicInformation, PowerSource } from '@matter/main/clusters';
|
|
13
13
|
import { createZip, isValidArray, isValidNumber, isValidObject, isValidString, isValidBoolean, withTimeout, hasParameter } from './utils/export.js';
|
|
14
14
|
import { plg } from './matterbridgeTypes.js';
|
|
15
|
-
import { capitalizeFirstLetter } from './matterbridgeEndpointHelpers.js';
|
|
15
|
+
import { capitalizeFirstLetter, getAttribute } from './matterbridgeEndpointHelpers.js';
|
|
16
16
|
import { cliEmitter, lastCpuUsage } from './cliEmitter.js';
|
|
17
17
|
export const WS_ID_LOG = 0;
|
|
18
18
|
export const WS_ID_REFRESH_NEEDED = 1;
|
|
@@ -294,12 +294,12 @@ export class Frontend extends EventEmitter {
|
|
|
294
294
|
this.expressApp.get('/api/view-mblog', async (req, res) => {
|
|
295
295
|
this.log.debug('The frontend sent /api/view-mblog');
|
|
296
296
|
try {
|
|
297
|
-
const data = await fs.readFile(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.
|
|
297
|
+
const data = await fs.readFile(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterbridgeLoggerFile), 'utf8');
|
|
298
298
|
res.type('text/plain');
|
|
299
299
|
res.send(data);
|
|
300
300
|
}
|
|
301
301
|
catch (error) {
|
|
302
|
-
this.log.error(`Error reading matterbridge log file ${this.matterbridge.
|
|
302
|
+
this.log.error(`Error reading matterbridge log file ${this.matterbridge.matterbridgeLoggerFile}: ${error instanceof Error ? error.message : error}`);
|
|
303
303
|
res.status(500).send('Error reading matterbridge log file. Please enable the matterbridge log on file in the settings.');
|
|
304
304
|
}
|
|
305
305
|
});
|
|
@@ -323,31 +323,31 @@ export class Frontend extends EventEmitter {
|
|
|
323
323
|
res.send(data);
|
|
324
324
|
}
|
|
325
325
|
catch (error) {
|
|
326
|
-
this.log.error(`Error reading shelly log file ${this.matterbridge.
|
|
326
|
+
this.log.error(`Error reading shelly log file ${this.matterbridge.matterbridgeLoggerFile}: ${error instanceof Error ? error.message : error}`);
|
|
327
327
|
res.status(500).send('Error reading shelly log file. Please create the shelly system log before loading it.');
|
|
328
328
|
}
|
|
329
329
|
});
|
|
330
330
|
this.expressApp.get('/api/download-mblog', async (req, res) => {
|
|
331
|
-
this.log.debug(`The frontend sent /api/download-mblog ${path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.
|
|
331
|
+
this.log.debug(`The frontend sent /api/download-mblog ${path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterbridgeLoggerFile)}`);
|
|
332
332
|
try {
|
|
333
|
-
await fs.access(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.
|
|
334
|
-
const data = await fs.readFile(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.
|
|
335
|
-
await fs.writeFile(path.join(os.tmpdir(), this.matterbridge.
|
|
333
|
+
await fs.access(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterbridgeLoggerFile), fs.constants.F_OK);
|
|
334
|
+
const data = await fs.readFile(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterbridgeLoggerFile), 'utf8');
|
|
335
|
+
await fs.writeFile(path.join(os.tmpdir(), this.matterbridge.matterbridgeLoggerFile), data, 'utf-8');
|
|
336
336
|
}
|
|
337
337
|
catch (error) {
|
|
338
|
-
await fs.writeFile(path.join(os.tmpdir(), this.matterbridge.
|
|
338
|
+
await fs.writeFile(path.join(os.tmpdir(), this.matterbridge.matterbridgeLoggerFile), 'Enable the matterbridge log on file in the settings to download the matterbridge log.', 'utf-8');
|
|
339
339
|
this.log.debug(`Error in /api/download-mblog: ${error instanceof Error ? error.message : error}`);
|
|
340
340
|
}
|
|
341
341
|
res.type('text/plain');
|
|
342
|
-
res.download(path.join(os.tmpdir(), this.matterbridge.
|
|
342
|
+
res.download(path.join(os.tmpdir(), this.matterbridge.matterbridgeLoggerFile), 'matterbridge.log', (error) => {
|
|
343
343
|
if (error) {
|
|
344
|
-
this.log.error(`Error downloading log file ${this.matterbridge.
|
|
344
|
+
this.log.error(`Error downloading log file ${this.matterbridge.matterbridgeLoggerFile}: ${error instanceof Error ? error.message : error}`);
|
|
345
345
|
res.status(500).send('Error downloading the matterbridge log file');
|
|
346
346
|
}
|
|
347
347
|
});
|
|
348
348
|
});
|
|
349
349
|
this.expressApp.get('/api/download-mjlog', async (req, res) => {
|
|
350
|
-
this.log.debug(`The frontend sent /api/download-mjlog ${path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.
|
|
350
|
+
this.log.debug(`The frontend sent /api/download-mjlog ${path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterbridgeLoggerFile)}`);
|
|
351
351
|
try {
|
|
352
352
|
await fs.access(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterLoggerFile), fs.constants.F_OK);
|
|
353
353
|
const data = await fs.readFile(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterLoggerFile), 'utf8');
|
|
@@ -419,8 +419,8 @@ export class Frontend extends EventEmitter {
|
|
|
419
419
|
await createZip(path.join(os.tmpdir(), `matterbridge.pluginconfig.zip`), path.relative(process.cwd(), path.join(this.matterbridge.matterbridgeDirectory, '*.config.json')));
|
|
420
420
|
res.download(path.join(os.tmpdir(), `matterbridge.pluginconfig.zip`), `matterbridge.pluginconfig.zip`, (error) => {
|
|
421
421
|
if (error) {
|
|
422
|
-
this.log.error(`Error downloading file matterbridge.
|
|
423
|
-
res.status(500).send('Error downloading the matterbridge plugin
|
|
422
|
+
this.log.error(`Error downloading file matterbridge.pluginconfig.zip: ${error instanceof Error ? error.message : error}`);
|
|
423
|
+
res.status(500).send('Error downloading the matterbridge plugin config file');
|
|
424
424
|
}
|
|
425
425
|
});
|
|
426
426
|
});
|
|
@@ -635,40 +635,23 @@ export class Frontend extends EventEmitter {
|
|
|
635
635
|
getClusterTextFromDevice(device) {
|
|
636
636
|
if (!device.lifecycle.isReady || device.construction.status !== Lifecycle.Status.Active)
|
|
637
637
|
return '';
|
|
638
|
-
const getAttribute = (device, cluster, attribute) => {
|
|
639
|
-
let value = undefined;
|
|
640
|
-
Object.entries(device.state)
|
|
641
|
-
.filter(([clusterName]) => clusterName.toLowerCase() === cluster.toLowerCase())
|
|
642
|
-
.forEach(([, clusterAttributes]) => {
|
|
643
|
-
Object.entries(clusterAttributes)
|
|
644
|
-
.filter(([attributeName]) => attributeName.toLowerCase() === attribute.toLowerCase())
|
|
645
|
-
.forEach(([, attributeValue]) => {
|
|
646
|
-
value = attributeValue;
|
|
647
|
-
});
|
|
648
|
-
});
|
|
649
|
-
if (value === undefined)
|
|
650
|
-
this.log.error(`Cluster ${cluster} or attribute ${attribute} not found in device ${device.deviceName}`);
|
|
651
|
-
return value;
|
|
652
|
-
};
|
|
653
638
|
const getUserLabel = (device) => {
|
|
654
639
|
const labelList = getAttribute(device, 'userLabel', 'labelList');
|
|
655
|
-
if (
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
return '';
|
|
640
|
+
if (labelList) {
|
|
641
|
+
const composed = labelList.find((entry) => entry.label === 'composed');
|
|
642
|
+
if (composed)
|
|
643
|
+
return 'Composed: ' + composed.value;
|
|
644
|
+
}
|
|
645
|
+
return '';
|
|
662
646
|
};
|
|
663
647
|
const getFixedLabel = (device) => {
|
|
664
648
|
const labelList = getAttribute(device, 'fixedLabel', 'labelList');
|
|
665
|
-
if (
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
return '';
|
|
649
|
+
if (labelList) {
|
|
650
|
+
const composed = labelList.find((entry) => entry.label === 'composed');
|
|
651
|
+
if (composed)
|
|
652
|
+
return 'Composed: ' + composed.value;
|
|
653
|
+
}
|
|
654
|
+
return '';
|
|
672
655
|
};
|
|
673
656
|
let attributes = '';
|
|
674
657
|
let supportedModes = [];
|
|
@@ -697,8 +680,6 @@ export class Frontend extends EventEmitter {
|
|
|
697
680
|
const supportedMode = supportedModes.find((mode) => mode.mode === attributeValue);
|
|
698
681
|
if (supportedMode)
|
|
699
682
|
attributes += `Mode: ${supportedMode.label} `;
|
|
700
|
-
else
|
|
701
|
-
attributes += `Mode: ${attributeValue} `;
|
|
702
683
|
}
|
|
703
684
|
const operationalStateClusters = ['operationalState', 'rvcOperationalState'];
|
|
704
685
|
if (operationalStateClusters.includes(clusterName) && attributeName === 'operationalState')
|
|
@@ -1102,10 +1083,7 @@ export class Frontend extends EventEmitter {
|
|
|
1102
1083
|
}
|
|
1103
1084
|
this.log.info(`Saving config for plugin ${plg}${data.params.pluginName}${nf}...`);
|
|
1104
1085
|
const plugin = this.matterbridge.plugins.get(data.params.pluginName);
|
|
1105
|
-
if (
|
|
1106
|
-
this.log.warn(`Plugin ${plg}${data.params.pluginName}${wr} not found in matterbridge`);
|
|
1107
|
-
}
|
|
1108
|
-
else {
|
|
1086
|
+
if (plugin) {
|
|
1109
1087
|
this.matterbridge.plugins.saveConfigFromJson(plugin, data.params.formData, true);
|
|
1110
1088
|
this.wssSendSnackbarMessage(`Saved config for plugin ${data.params.pluginName}`);
|
|
1111
1089
|
this.wssSendRefreshRequired('pluginsRestart');
|
|
@@ -1191,7 +1169,7 @@ export class Frontend extends EventEmitter {
|
|
|
1191
1169
|
this.matterbridge.matterbridgeManualPairingCode = pairingCodes?.manualPairingCode;
|
|
1192
1170
|
this.wssSendRefreshRequired('matterbridgeAdvertise');
|
|
1193
1171
|
this.wssSendSnackbarMessage(`Started fabrics share`, 0);
|
|
1194
|
-
client.send(JSON.stringify({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, response: pairingCodes }));
|
|
1172
|
+
client.send(JSON.stringify({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, response: pairingCodes, success: true }));
|
|
1195
1173
|
}
|
|
1196
1174
|
else if (data.method === '/api/stopadvertise') {
|
|
1197
1175
|
await this.matterbridge.stopAdvertiseServerNode(this.matterbridge.serverNode);
|
|
@@ -1338,7 +1316,7 @@ export class Frontend extends EventEmitter {
|
|
|
1338
1316
|
this.matterbridge.matterbridgeInformation.fileLogger = data.params.value;
|
|
1339
1317
|
await this.matterbridge.nodeContext?.set('matterbridgeFileLog', data.params.value);
|
|
1340
1318
|
if (data.params.value)
|
|
1341
|
-
AnsiLogger.setGlobalLogfile(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.
|
|
1319
|
+
AnsiLogger.setGlobalLogfile(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterbridgeLoggerFile), this.matterbridge.matterbridgeInformation.loggerLevel, true);
|
|
1342
1320
|
else
|
|
1343
1321
|
AnsiLogger.setGlobalLogfile(undefined);
|
|
1344
1322
|
client.send(JSON.stringify({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, success: true }));
|
|
@@ -1450,14 +1428,15 @@ export class Frontend extends EventEmitter {
|
|
|
1450
1428
|
this.matterbridge.matterbridgeInformation.matterDiscriminator = data.params.value;
|
|
1451
1429
|
await this.matterbridge.nodeContext?.set('matterdiscriminator', data.params.value);
|
|
1452
1430
|
this.wssSendRestartRequired();
|
|
1431
|
+
client.send(JSON.stringify({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, success: true }));
|
|
1453
1432
|
}
|
|
1454
1433
|
else {
|
|
1455
1434
|
this.log.debug(`Reset matter commissioning discriminator to ${CYAN}undefined${db}`);
|
|
1456
1435
|
this.matterbridge.matterbridgeInformation.matterDiscriminator = undefined;
|
|
1457
1436
|
await this.matterbridge.nodeContext?.remove('matterdiscriminator');
|
|
1458
1437
|
this.wssSendRestartRequired();
|
|
1438
|
+
client.send(JSON.stringify({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, success: false }));
|
|
1459
1439
|
}
|
|
1460
|
-
client.send(JSON.stringify({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, success: true }));
|
|
1461
1440
|
break;
|
|
1462
1441
|
case 'setmatterpasscode':
|
|
1463
1442
|
data.params.value = isValidString(data.params.value) ? parseInt(data.params.value) : 0;
|
|
@@ -1466,14 +1445,15 @@ export class Frontend extends EventEmitter {
|
|
|
1466
1445
|
this.log.debug(`Set matter commissioning passcode to ${CYAN}${data.params.value}${db}`);
|
|
1467
1446
|
await this.matterbridge.nodeContext?.set('matterpasscode', data.params.value);
|
|
1468
1447
|
this.wssSendRestartRequired();
|
|
1448
|
+
client.send(JSON.stringify({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, success: true }));
|
|
1469
1449
|
}
|
|
1470
1450
|
else {
|
|
1471
1451
|
this.log.debug(`Reset matter commissioning passcode to ${CYAN}undefined${db}`);
|
|
1472
1452
|
this.matterbridge.matterbridgeInformation.matterPasscode = undefined;
|
|
1473
1453
|
await this.matterbridge.nodeContext?.remove('matterpasscode');
|
|
1474
1454
|
this.wssSendRestartRequired();
|
|
1455
|
+
client.send(JSON.stringify({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, success: false }));
|
|
1475
1456
|
}
|
|
1476
|
-
client.send(JSON.stringify({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, success: true }));
|
|
1477
1457
|
break;
|
|
1478
1458
|
case 'setvirtualmode':
|
|
1479
1459
|
if (isValidString(data.params.value, 1) && ['disabled', 'light', 'outlet', 'switch', 'mounted_switch'].includes(data.params.value)) {
|
package/dist/matterbridge.js
CHANGED
|
@@ -99,7 +99,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
99
99
|
edge = true;
|
|
100
100
|
failCountLimit = hasParameter('shelly') ? 600 : 120;
|
|
101
101
|
log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4, logLevel: hasParameter('debug') ? "debug" : "info" });
|
|
102
|
-
|
|
102
|
+
matterbridgeLoggerFile = 'matterbridge' + (getParameter('profile') ? '.' + getParameter('profile') : '') + '.log';
|
|
103
103
|
matterLoggerFile = 'matter' + (getParameter('profile') ? '.' + getParameter('profile') : '') + '.log';
|
|
104
104
|
plugins;
|
|
105
105
|
devices;
|
|
@@ -346,7 +346,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
346
346
|
MatterbridgeEndpoint.logLevel = this.log.logLevel;
|
|
347
347
|
this.matterbridgeInformation.loggerLevel = this.log.logLevel;
|
|
348
348
|
if (hasParameter('filelogger') || (await this.nodeContext.get('matterbridgeFileLog', false))) {
|
|
349
|
-
AnsiLogger.setGlobalLogfile(path.join(this.matterbridgeDirectory, this.
|
|
349
|
+
AnsiLogger.setGlobalLogfile(path.join(this.matterbridgeDirectory, this.matterbridgeLoggerFile), this.log.logLevel, true);
|
|
350
350
|
this.matterbridgeInformation.fileLogger = true;
|
|
351
351
|
}
|
|
352
352
|
this.log.notice('Matterbridge is starting...');
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "matterbridge",
|
|
3
|
-
"version": "3.1.2-dev-
|
|
3
|
+
"version": "3.1.2-dev-20250706-6c6481e",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "matterbridge",
|
|
9
|
-
"version": "3.1.2-dev-
|
|
9
|
+
"version": "3.1.2-dev-20250706-6c6481e",
|
|
10
10
|
"license": "Apache-2.0",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@matter/main": "0.15.1",
|
package/package.json
CHANGED