matterbridge 3.0.0-edge.8 → 3.0.1-dev-20250430-a3ea2b7
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 +52 -9
- package/README-DEV.md +4 -0
- package/README-DOCKER.md +21 -12
- package/README-SERVICE.md +27 -21
- package/README.md +102 -6
- package/dist/cli.js +4 -1
- package/dist/frontend.js +91 -16
- package/dist/matterbridge.js +53 -33
- package/dist/matterbridgeEndpoint.js +18 -2
- package/dist/matterbridgeEndpointHelpers.js +14 -0
- package/dist/matterbridgePlatform.js +2 -2
- package/dist/update.js +18 -0
- package/dist/utils/parameter.js +39 -7
- package/dist/utils/wait.js +2 -0
- package/frontend/build/asset-manifest.json +6 -6
- package/frontend/build/bmc-button.svg +22 -0
- package/frontend/build/discord.svg +5 -0
- package/frontend/build/index.html +1 -1
- package/frontend/build/static/css/{main.ea7910e9.css → main.944b63c3.css} +2 -2
- package/frontend/build/static/css/main.944b63c3.css.map +1 -0
- package/frontend/build/static/js/{main.e11d6bb4.js → main.356788d7.js} +12 -12
- package/frontend/build/static/js/{main.e11d6bb4.js.map → main.356788d7.js.map} +1 -1
- package/npm-shrinkwrap.json +300 -362
- package/package.json +4 -4
- package/tsconfig.jest.json +8 -0
- package/README-EDGE.md +0 -74
- package/frontend/build/static/css/main.ea7910e9.css.map +0 -1
- /package/frontend/build/static/js/{main.e11d6bb4.js.LICENSE.txt → main.356788d7.js.LICENSE.txt} +0 -0
package/dist/frontend.js
CHANGED
|
@@ -11,7 +11,7 @@ import { AnsiLogger, stringify, debugStringify, CYAN, db, er, nf, rs, UNDERLINE,
|
|
|
11
11
|
import { createZip, deepCopy, isValidArray, isValidNumber, isValidObject, isValidString } from './utils/export.js';
|
|
12
12
|
import { plg } from './matterbridgeTypes.js';
|
|
13
13
|
import { hasParameter } from './utils/export.js';
|
|
14
|
-
import { BridgedDeviceBasicInformation } from '@matter/main/clusters';
|
|
14
|
+
import { BridgedDeviceBasicInformation, PowerSource } from '@matter/main/clusters';
|
|
15
15
|
export const WS_ID_LOG = 0;
|
|
16
16
|
export const WS_ID_REFRESH_NEEDED = 1;
|
|
17
17
|
export const WS_ID_RESTART_NEEDED = 2;
|
|
@@ -369,27 +369,55 @@ export class Frontend {
|
|
|
369
369
|
});
|
|
370
370
|
res.json(data);
|
|
371
371
|
});
|
|
372
|
-
this.expressApp.get('/api/view-
|
|
373
|
-
this.log.debug('The frontend sent /api/
|
|
372
|
+
this.expressApp.get('/api/view-mblog', async (req, res) => {
|
|
373
|
+
this.log.debug('The frontend sent /api/view-mblog');
|
|
374
374
|
try {
|
|
375
375
|
const data = await fs.readFile(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterbrideLoggerFile), 'utf8');
|
|
376
376
|
res.type('text/plain');
|
|
377
377
|
res.send(data);
|
|
378
378
|
}
|
|
379
379
|
catch (error) {
|
|
380
|
-
this.log.error(`Error reading log file ${this.matterbridge.matterbrideLoggerFile}: ${error instanceof Error ? error.message : error}`);
|
|
381
|
-
res.status(500).send('Error reading log file');
|
|
380
|
+
this.log.error(`Error reading matterbridge log file ${this.matterbridge.matterbrideLoggerFile}: ${error instanceof Error ? error.message : error}`);
|
|
381
|
+
res.status(500).send('Error reading matterbridge log file. Please enable the matterbridge log on file in the settings.');
|
|
382
|
+
}
|
|
383
|
+
});
|
|
384
|
+
this.expressApp.get('/api/view-mjlog', async (req, res) => {
|
|
385
|
+
this.log.debug('The frontend sent /api/view-mjlog');
|
|
386
|
+
try {
|
|
387
|
+
const data = await fs.readFile(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterLoggerFile), 'utf8');
|
|
388
|
+
res.type('text/plain');
|
|
389
|
+
res.send(data);
|
|
390
|
+
}
|
|
391
|
+
catch (error) {
|
|
392
|
+
this.log.error(`Error reading matter log file ${this.matterbridge.matterLoggerFile}: ${error instanceof Error ? error.message : error}`);
|
|
393
|
+
res.status(500).send('Error reading matter log file. Please enable the matter log on file in the settings.');
|
|
394
|
+
}
|
|
395
|
+
});
|
|
396
|
+
this.expressApp.get('/api/shellyviewsystemlog', async (req, res) => {
|
|
397
|
+
this.log.debug('The frontend sent /api/shellyviewsystemlog');
|
|
398
|
+
try {
|
|
399
|
+
const data = await fs.readFile(path.join(this.matterbridge.matterbridgeDirectory, 'shelly.log'), 'utf8');
|
|
400
|
+
res.type('text/plain');
|
|
401
|
+
res.send(data);
|
|
402
|
+
}
|
|
403
|
+
catch (error) {
|
|
404
|
+
this.log.error(`Error reading shelly log file ${this.matterbridge.matterbrideLoggerFile}: ${error instanceof Error ? error.message : error}`);
|
|
405
|
+
res.status(500).send('Error reading shelly log file. Please create the shelly system log before loading it.');
|
|
382
406
|
}
|
|
383
407
|
});
|
|
384
408
|
this.expressApp.get('/api/download-mblog', async (req, res) => {
|
|
385
|
-
this.log.debug(
|
|
409
|
+
this.log.debug(`The frontend sent /api/download-mblog ${path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterbrideLoggerFile)}`);
|
|
386
410
|
try {
|
|
387
411
|
await fs.access(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterbrideLoggerFile), fs.constants.F_OK);
|
|
412
|
+
const data = await fs.readFile(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterbrideLoggerFile), 'utf8');
|
|
413
|
+
await fs.writeFile(path.join(os.tmpdir(), this.matterbridge.matterbrideLoggerFile), data, 'utf-8');
|
|
388
414
|
}
|
|
389
415
|
catch (error) {
|
|
390
|
-
fs.
|
|
416
|
+
await fs.writeFile(path.join(os.tmpdir(), this.matterbridge.matterbrideLoggerFile), 'Enable the matterbridge log on file in the settings to download the matterbridge log.', 'utf-8');
|
|
417
|
+
this.log.debug(`Error in /api/download-mblog: ${error instanceof Error ? error.message : error}`);
|
|
391
418
|
}
|
|
392
|
-
res.
|
|
419
|
+
res.type('text/plain');
|
|
420
|
+
res.download(path.join(os.tmpdir(), this.matterbridge.matterbrideLoggerFile), 'matterbridge.log', (error) => {
|
|
393
421
|
if (error) {
|
|
394
422
|
this.log.error(`Error downloading log file ${this.matterbridge.matterbrideLoggerFile}: ${error instanceof Error ? error.message : error}`);
|
|
395
423
|
res.status(500).send('Error downloading the matterbridge log file');
|
|
@@ -397,14 +425,18 @@ export class Frontend {
|
|
|
397
425
|
});
|
|
398
426
|
});
|
|
399
427
|
this.expressApp.get('/api/download-mjlog', async (req, res) => {
|
|
400
|
-
this.log.debug(
|
|
428
|
+
this.log.debug(`The frontend sent /api/download-mjlog ${path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterbrideLoggerFile)}`);
|
|
401
429
|
try {
|
|
402
430
|
await fs.access(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterLoggerFile), fs.constants.F_OK);
|
|
431
|
+
const data = await fs.readFile(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterLoggerFile), 'utf8');
|
|
432
|
+
await fs.writeFile(path.join(os.tmpdir(), this.matterbridge.matterLoggerFile), data, 'utf-8');
|
|
403
433
|
}
|
|
404
434
|
catch (error) {
|
|
405
|
-
fs.
|
|
435
|
+
await fs.writeFile(path.join(os.tmpdir(), this.matterbridge.matterLoggerFile), 'Enable the matter log on file in the settings to download the matter log.', 'utf-8');
|
|
436
|
+
this.log.debug(`Error in /api/download-mblog: ${error instanceof Error ? error.message : error}`);
|
|
406
437
|
}
|
|
407
|
-
res.
|
|
438
|
+
res.type('text/plain');
|
|
439
|
+
res.download(path.join(os.tmpdir(), this.matterbridge.matterLoggerFile), 'matter.log', (error) => {
|
|
408
440
|
if (error) {
|
|
409
441
|
this.log.error(`Error downloading log file ${this.matterbridge.matterLoggerFile}: ${error instanceof Error ? error.message : error}`);
|
|
410
442
|
res.status(500).send('Error downloading the matter log file');
|
|
@@ -415,11 +447,15 @@ export class Frontend {
|
|
|
415
447
|
this.log.debug('The frontend sent /api/shellydownloadsystemlog');
|
|
416
448
|
try {
|
|
417
449
|
await fs.access(path.join(this.matterbridge.matterbridgeDirectory, 'shelly.log'), fs.constants.F_OK);
|
|
450
|
+
const data = await fs.readFile(path.join(this.matterbridge.matterbridgeDirectory, 'shelly.log'), 'utf8');
|
|
451
|
+
await fs.writeFile(path.join(os.tmpdir(), 'shelly.log'), data, 'utf-8');
|
|
418
452
|
}
|
|
419
453
|
catch (error) {
|
|
420
|
-
fs.
|
|
454
|
+
await fs.writeFile(path.join(os.tmpdir(), 'shelly.log'), 'Create the Shelly system log before downloading it.', 'utf-8');
|
|
455
|
+
this.log.debug(`Error in /api/shellydownloadsystemlog: ${error instanceof Error ? error.message : error}`);
|
|
421
456
|
}
|
|
422
|
-
res.
|
|
457
|
+
res.type('text/plain');
|
|
458
|
+
res.download(path.join(os.tmpdir(), 'shelly.log'), 'shelly.log', (error) => {
|
|
423
459
|
if (error) {
|
|
424
460
|
this.log.error(`Error downloading Shelly system log file: ${error instanceof Error ? error.message : error}`);
|
|
425
461
|
res.status(500).send('Error downloading Shelly system log file');
|
|
@@ -814,9 +850,8 @@ export class Frontend {
|
|
|
814
850
|
res.status(500).send(`Error uploading or installing plugin package ${filename}`);
|
|
815
851
|
}
|
|
816
852
|
});
|
|
817
|
-
this.expressApp.
|
|
853
|
+
this.expressApp.use((req, res) => {
|
|
818
854
|
this.log.debug('The frontend sent:', req.url);
|
|
819
|
-
this.log.debug('Response send file:', path.join(this.matterbridge.rootDirectory, 'frontend/build/index.html'));
|
|
820
855
|
res.sendFile(path.join(this.matterbridge.rootDirectory, 'frontend/build/index.html'));
|
|
821
856
|
});
|
|
822
857
|
this.log.debug(`Frontend initialized on port ${YELLOW}${this.port}${db} static ${UNDERLINE}${path.join(this.matterbridge.rootDirectory, 'frontend/build')}${UNDERLINEOFF}${rs}`);
|
|
@@ -919,6 +954,28 @@ export class Frontend {
|
|
|
919
954
|
return true;
|
|
920
955
|
return false;
|
|
921
956
|
}
|
|
957
|
+
getPowerSource(device) {
|
|
958
|
+
if (!device.lifecycle.isReady || device.construction.status !== Lifecycle.Status.Active)
|
|
959
|
+
return undefined;
|
|
960
|
+
const powerSource = (device) => {
|
|
961
|
+
const featureMap = device.getAttribute(PowerSource.Cluster.id, 'featureMap');
|
|
962
|
+
if (featureMap.wired) {
|
|
963
|
+
const wiredCurrentType = device.getAttribute(PowerSource.Cluster.id, 'wiredCurrentType');
|
|
964
|
+
return ['ac', 'dc'][wiredCurrentType];
|
|
965
|
+
}
|
|
966
|
+
if (featureMap.battery) {
|
|
967
|
+
const batChargeLevel = device.getAttribute(PowerSource.Cluster.id, 'batChargeLevel');
|
|
968
|
+
return ['ok', 'warning', 'critical'][batChargeLevel];
|
|
969
|
+
}
|
|
970
|
+
return;
|
|
971
|
+
};
|
|
972
|
+
if (device.hasClusterServer(PowerSource.Cluster.id))
|
|
973
|
+
return powerSource(device);
|
|
974
|
+
for (const child of device.getChildEndpoints()) {
|
|
975
|
+
if (child.hasClusterServer(PowerSource.Cluster.id))
|
|
976
|
+
return powerSource(child);
|
|
977
|
+
}
|
|
978
|
+
}
|
|
922
979
|
getClusterTextFromDevice(device) {
|
|
923
980
|
if (!device.lifecycle.isReady || device.construction.status !== Lifecycle.Status.Active)
|
|
924
981
|
return '';
|
|
@@ -958,6 +1015,7 @@ export class Frontend {
|
|
|
958
1015
|
return '';
|
|
959
1016
|
};
|
|
960
1017
|
let attributes = '';
|
|
1018
|
+
let supportedModes = [];
|
|
961
1019
|
device.forEachAttribute((clusterName, clusterId, attributeName, attributeId, attributeValue) => {
|
|
962
1020
|
if (typeof attributeValue === 'undefined')
|
|
963
1021
|
return;
|
|
@@ -975,6 +1033,20 @@ export class Frontend {
|
|
|
975
1033
|
attributes += `Heat to: ${attributeValue / 100}°C `;
|
|
976
1034
|
if (clusterName === 'thermostat' && attributeName === 'occupiedCoolingSetpoint' && isValidNumber(attributeValue))
|
|
977
1035
|
attributes += `Cool to: ${attributeValue / 100}°C `;
|
|
1036
|
+
const modeClusters = ['modeSelect', 'rvcRunMode', 'rvcCleanMode', 'laundryWasherMode', 'ovenMode', 'microwaveOvenMode'];
|
|
1037
|
+
if (modeClusters.includes(clusterName) && attributeName === 'supportedModes') {
|
|
1038
|
+
supportedModes = attributeValue;
|
|
1039
|
+
}
|
|
1040
|
+
if (modeClusters.includes(clusterName) && attributeName === 'currentMode') {
|
|
1041
|
+
const supportedMode = supportedModes.find((mode) => mode.mode === attributeValue);
|
|
1042
|
+
if (supportedMode)
|
|
1043
|
+
attributes += `Mode: ${supportedMode.label} `;
|
|
1044
|
+
else
|
|
1045
|
+
attributes += `Mode: ${attributeValue} `;
|
|
1046
|
+
}
|
|
1047
|
+
const operationalStateClusters = ['operationalState', 'rvcOperationalState'];
|
|
1048
|
+
if (operationalStateClusters.includes(clusterName) && attributeName === 'operationalState')
|
|
1049
|
+
attributes += `OpState: ${attributeValue} `;
|
|
978
1050
|
if (clusterName === 'pumpConfigurationAndControl' && attributeName === 'operationMode')
|
|
979
1051
|
attributes += `Mode: ${attributeValue} `;
|
|
980
1052
|
if (clusterName === 'valveConfigurationAndControl' && attributeName === 'currentState')
|
|
@@ -1053,6 +1125,7 @@ export class Frontend {
|
|
|
1053
1125
|
changelog: plugin.changelog,
|
|
1054
1126
|
funding: plugin.funding,
|
|
1055
1127
|
latestVersion: plugin.latestVersion,
|
|
1128
|
+
serialNumber: plugin.serialNumber,
|
|
1056
1129
|
locked: plugin.locked,
|
|
1057
1130
|
error: plugin.error,
|
|
1058
1131
|
enabled: plugin.enabled,
|
|
@@ -1244,6 +1317,7 @@ export class Frontend {
|
|
|
1244
1317
|
configUrl: device.configUrl,
|
|
1245
1318
|
uniqueId: device.uniqueId,
|
|
1246
1319
|
reachable: this.getReachability(device),
|
|
1320
|
+
powerSource: this.getPowerSource(device),
|
|
1247
1321
|
cluster: cluster,
|
|
1248
1322
|
});
|
|
1249
1323
|
});
|
|
@@ -1396,7 +1470,7 @@ export class Frontend {
|
|
|
1396
1470
|
return;
|
|
1397
1471
|
}
|
|
1398
1472
|
this.log.notice(`Action ${CYAN}${data.params.action}${nt}${data.params.value ? ' with ' + CYAN + data.params.value + nt : ''} for plugin ${CYAN}${plugin.name}${nt}`);
|
|
1399
|
-
plugin.platform?.onAction(data.params.action, data.params.value, data.params.id).catch((error) => {
|
|
1473
|
+
plugin.platform?.onAction(data.params.action, data.params.value, data.params.id, data.params.formData).catch((error) => {
|
|
1400
1474
|
this.log.error(`Error in plugin ${plugin.name} action ${data.params.action}: ${error}`);
|
|
1401
1475
|
});
|
|
1402
1476
|
}
|
|
@@ -1503,6 +1577,7 @@ export class Frontend {
|
|
|
1503
1577
|
message = message.replace(/[\t\n]/g, '');
|
|
1504
1578
|
message = message.replace(/[\x00-\x1F\x7F]/g, '');
|
|
1505
1579
|
message = message.replace(/\\"/g, '"');
|
|
1580
|
+
message = message.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
|
1506
1581
|
const maxContinuousLength = 100;
|
|
1507
1582
|
const keepStartLength = 20;
|
|
1508
1583
|
const keepEndLength = 20;
|
package/dist/matterbridge.js
CHANGED
|
@@ -5,7 +5,7 @@ import EventEmitter from 'node:events';
|
|
|
5
5
|
import { inspect } from 'node:util';
|
|
6
6
|
import { AnsiLogger, UNDERLINE, UNDERLINEOFF, YELLOW, db, debugStringify, BRIGHT, RESET, er, nf, rs, wr, RED, GREEN, zb, CYAN } from './logger/export.js';
|
|
7
7
|
import { NodeStorageManager } from './storage/export.js';
|
|
8
|
-
import { getParameter, getIntParameter, hasParameter, copyDirectory, withTimeout } from './utils/export.js';
|
|
8
|
+
import { getParameter, getIntParameter, hasParameter, copyDirectory, withTimeout, waiter } from './utils/export.js';
|
|
9
9
|
import { logInterfaces, getGlobalNodeModules } from './utils/network.js';
|
|
10
10
|
import { PluginManager } from './pluginManager.js';
|
|
11
11
|
import { DeviceManager } from './deviceManager.js';
|
|
@@ -51,6 +51,8 @@ export class Matterbridge extends EventEmitter {
|
|
|
51
51
|
globalModulesDirectory: '',
|
|
52
52
|
matterbridgeVersion: '',
|
|
53
53
|
matterbridgeLatestVersion: '',
|
|
54
|
+
matterbridgeDevVersion: '',
|
|
55
|
+
matterbridgeSerialNumber: '',
|
|
54
56
|
matterbridgeQrPairingCode: undefined,
|
|
55
57
|
matterbridgeManualPairingCode: undefined,
|
|
56
58
|
matterbridgeFabricInformations: [],
|
|
@@ -85,6 +87,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
85
87
|
globalModulesDirectory = '';
|
|
86
88
|
matterbridgeVersion = '';
|
|
87
89
|
matterbridgeLatestVersion = '';
|
|
90
|
+
matterbridgeDevVersion = '';
|
|
88
91
|
matterbridgeQrPairingCode = undefined;
|
|
89
92
|
matterbridgeManualPairingCode = undefined;
|
|
90
93
|
matterbridgeFabricInformations = undefined;
|
|
@@ -491,6 +494,13 @@ export class Matterbridge extends EventEmitter {
|
|
|
491
494
|
- nosudo: force not to use sudo to install or update packages if the internal logic fails
|
|
492
495
|
- norestore: force not to automatically restore the matterbridge node storage and the matter storage from backup if it is corrupted
|
|
493
496
|
- ssl: enable SSL for the frontend and WebSockerServer (certificates in .matterbridge/certs directory cert.pem, key.pem and ca.pem (optional))
|
|
497
|
+
- vendorId: override the default vendorId 0xfff1
|
|
498
|
+
- vendorName: override the default vendorName "Matterbridge"
|
|
499
|
+
- productId: override the default productId 0x8000
|
|
500
|
+
- productName: override the default productName "Matterbridge aggregator"
|
|
501
|
+
- service: enable the service mode (used in the systemctl configuration file)
|
|
502
|
+
- docker: enable the docker mode (used in the Dockerfile to build the docker image)
|
|
503
|
+
- homedir: override the home directory (default: os.homedir())
|
|
494
504
|
- add [plugin path]: register the plugin from the given absolute or relative path
|
|
495
505
|
- add [plugin name]: register the globally installed plugin with the given name
|
|
496
506
|
- remove [plugin path]: remove the plugin from the given absolute or relative path
|
|
@@ -625,7 +635,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
625
635
|
this.checkUpdateInterval = setInterval(async () => {
|
|
626
636
|
const { checkUpdates } = await import('./update.js');
|
|
627
637
|
checkUpdates(this);
|
|
628
|
-
},
|
|
638
|
+
}, 12 * 60 * 60 * 1000).unref();
|
|
629
639
|
if (hasParameter('test')) {
|
|
630
640
|
this.bridgeMode = 'bridge';
|
|
631
641
|
MatterbridgeEndpoint.bridgeMode = 'bridge';
|
|
@@ -687,11 +697,15 @@ export class Matterbridge extends EventEmitter {
|
|
|
687
697
|
process.removeAllListeners('uncaughtException');
|
|
688
698
|
process.removeAllListeners('unhandledRejection');
|
|
689
699
|
this.exceptionHandler = async (error) => {
|
|
690
|
-
|
|
700
|
+
const errorMessage = error instanceof Error ? error.message : error;
|
|
701
|
+
const errorInspect = inspect(error, { depth: 10 });
|
|
702
|
+
this.log.error(`Unhandled Exception detected: ${errorMessage}\nstack: ${errorInspect}}`);
|
|
691
703
|
};
|
|
692
704
|
process.on('uncaughtException', this.exceptionHandler);
|
|
693
705
|
this.rejectionHandler = async (reason, promise) => {
|
|
694
|
-
|
|
706
|
+
const errorMessage = reason instanceof Error ? reason.message : reason;
|
|
707
|
+
const errorInspect = inspect(reason, { depth: 10 });
|
|
708
|
+
this.log.error(`Unhandled Rejection detected: ${promise}\nreason: ${errorMessage}\nstack: ${errorInspect}`);
|
|
695
709
|
};
|
|
696
710
|
process.on('unhandledRejection', this.rejectionHandler);
|
|
697
711
|
this.log.debug(`Registering SIGINT and SIGTERM signal handlers...`);
|
|
@@ -1165,6 +1179,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
1165
1179
|
plugin.device = device;
|
|
1166
1180
|
plugin.storageContext = await this.createServerNodeContext(plugin.name, device.deviceName, DeviceTypeId(device.deviceType), device.vendorId, device.vendorName, device.productId, device.productName);
|
|
1167
1181
|
plugin.serverNode = await this.createServerNode(plugin.storageContext, this.port ? this.port++ : undefined, this.passcode ? this.passcode++ : undefined, this.discriminator ? this.discriminator++ : undefined);
|
|
1182
|
+
plugin.serialNumber = await plugin.storageContext.get('serialNumber', '');
|
|
1168
1183
|
this.log.debug(`Adding ${plg}${plugin.name}${db}:${dev}${device.deviceName}${db} to ${plg}${plugin.name}${db} server node`);
|
|
1169
1184
|
await plugin.serverNode.add(device);
|
|
1170
1185
|
if (start)
|
|
@@ -1174,9 +1189,10 @@ export class Matterbridge extends EventEmitter {
|
|
|
1174
1189
|
async createDynamicPlugin(plugin, start = false) {
|
|
1175
1190
|
if (!plugin.locked) {
|
|
1176
1191
|
plugin.locked = true;
|
|
1177
|
-
plugin.storageContext = await this.createServerNodeContext(plugin.name, 'Matterbridge', bridge.code, this.aggregatorVendorId,
|
|
1192
|
+
plugin.storageContext = await this.createServerNodeContext(plugin.name, 'Matterbridge', bridge.code, this.aggregatorVendorId, this.aggregatorVendorName, this.aggregatorProductId, plugin.description);
|
|
1178
1193
|
plugin.serverNode = await this.createServerNode(plugin.storageContext, this.port ? this.port++ : undefined, this.passcode ? this.passcode++ : undefined, this.discriminator ? this.discriminator++ : undefined);
|
|
1179
1194
|
plugin.aggregatorNode = await this.createAggregatorNode(plugin.storageContext);
|
|
1195
|
+
plugin.serialNumber = await plugin.storageContext.get('serialNumber', '');
|
|
1180
1196
|
await plugin.serverNode.add(plugin.aggregatorNode);
|
|
1181
1197
|
if (start)
|
|
1182
1198
|
await this.startServerNode(plugin.serverNode);
|
|
@@ -1249,13 +1265,6 @@ export class Matterbridge extends EventEmitter {
|
|
|
1249
1265
|
async startChildbridge() {
|
|
1250
1266
|
if (!this.matterStorageManager)
|
|
1251
1267
|
throw new Error('No storage manager initialized');
|
|
1252
|
-
for (const plugin of this.plugins) {
|
|
1253
|
-
if (!plugin.enabled)
|
|
1254
|
-
continue;
|
|
1255
|
-
if (plugin.type === 'DynamicPlatform') {
|
|
1256
|
-
await this.createDynamicPlugin(plugin);
|
|
1257
|
-
}
|
|
1258
|
-
}
|
|
1259
1268
|
await this.startPlugins();
|
|
1260
1269
|
this.log.debug('Starting start matter interval in childbridge mode...');
|
|
1261
1270
|
let failCount = 0;
|
|
@@ -1358,6 +1367,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
1358
1367
|
this.matterStorageManager = await this.matterStorageService.open('Matterbridge');
|
|
1359
1368
|
this.log.info('Matter node storage manager "Matterbridge" created');
|
|
1360
1369
|
this.matterbridgeContext = await this.createServerNodeContext('Matterbridge', 'Matterbridge', bridge.code, this.aggregatorVendorId, this.aggregatorVendorName, this.aggregatorProductId, this.aggregatorProductName);
|
|
1370
|
+
this.matterbridgeInformation.matterbridgeSerialNumber = await this.matterbridgeContext.get('serialNumber', '');
|
|
1361
1371
|
this.log.info('Matter node storage started');
|
|
1362
1372
|
await this.backupMatterStorage(path.join(this.matterbridgeDirectory, this.matterStorageName), path.join(this.matterbridgeDirectory, this.matterStorageName + '.backup'));
|
|
1363
1373
|
}
|
|
@@ -1368,7 +1378,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
1368
1378
|
}
|
|
1369
1379
|
async stopMatterStorage() {
|
|
1370
1380
|
this.log.info('Closing matter node storage...');
|
|
1371
|
-
this.matterStorageManager?.close();
|
|
1381
|
+
await this.matterStorageManager?.close();
|
|
1372
1382
|
this.matterStorageService = undefined;
|
|
1373
1383
|
this.matterStorageManager = undefined;
|
|
1374
1384
|
this.matterbridgeContext = undefined;
|
|
@@ -1507,6 +1517,8 @@ export class Matterbridge extends EventEmitter {
|
|
|
1507
1517
|
}
|
|
1508
1518
|
}
|
|
1509
1519
|
setTimeout(() => {
|
|
1520
|
+
if (serverNode.lifecycle.isCommissioned)
|
|
1521
|
+
return;
|
|
1510
1522
|
if (this.bridgeMode === 'bridge') {
|
|
1511
1523
|
this.matterbridgeQrPairingCode = undefined;
|
|
1512
1524
|
this.matterbridgeManualPairingCode = undefined;
|
|
@@ -1516,10 +1528,12 @@ export class Matterbridge extends EventEmitter {
|
|
|
1516
1528
|
if (plugin) {
|
|
1517
1529
|
plugin.qrPairingCode = undefined;
|
|
1518
1530
|
plugin.manualPairingCode = undefined;
|
|
1519
|
-
this.frontend.wssSendRefreshRequired('plugins');
|
|
1520
1531
|
}
|
|
1521
1532
|
}
|
|
1533
|
+
this.frontend.wssSendRefreshRequired('plugins');
|
|
1522
1534
|
this.frontend.wssSendRefreshRequired('settings');
|
|
1535
|
+
this.frontend.wssSendRefreshRequired('fabrics');
|
|
1536
|
+
this.frontend.wssSendRefreshRequired('sessions');
|
|
1523
1537
|
this.frontend.wssSendSnackbarMessage(`Advertising on server node for ${storeId} stopped. Restart to commission.`, 0);
|
|
1524
1538
|
this.log.notice(`Advertising on server node for ${storeId} stopped. Restart to commission.`);
|
|
1525
1539
|
}, 15 * 60 * 1000).unref();
|
|
@@ -1651,16 +1665,17 @@ export class Matterbridge extends EventEmitter {
|
|
|
1651
1665
|
}
|
|
1652
1666
|
if (this.bridgeMode === 'bridge') {
|
|
1653
1667
|
this.log.debug(`Adding bridged endpoint ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} to Matterbridge aggregator node`);
|
|
1654
|
-
if (!this.aggregatorNode)
|
|
1668
|
+
if (!this.aggregatorNode) {
|
|
1655
1669
|
this.log.error('Aggregator node not found for Matterbridge');
|
|
1670
|
+
return;
|
|
1671
|
+
}
|
|
1656
1672
|
try {
|
|
1657
|
-
await this.aggregatorNode
|
|
1673
|
+
await this.aggregatorNode.add(device);
|
|
1658
1674
|
}
|
|
1659
1675
|
catch (error) {
|
|
1660
|
-
const errorMessage = error instanceof Error ? error.message :
|
|
1661
|
-
const
|
|
1662
|
-
|
|
1663
|
-
this.log.error(`Error adding bridged endpoint ${dev}${device.deviceName}${er} (${zb}${device.id}${er}) for plugin ${plg}${pluginName}${er}: ${error} ${errorMessage} ${errorStack} ${errorDebug}`);
|
|
1676
|
+
const errorMessage = error instanceof Error ? error.message : error;
|
|
1677
|
+
const errorInspect = inspect(error, { depth: 10 });
|
|
1678
|
+
this.log.error(`Error adding bridged endpoint ${dev}${device.deviceName}${er} (${zb}${device.id}${er}) for plugin ${plg}${pluginName}${er}: ${errorMessage}\nstack: ${errorInspect}`);
|
|
1664
1679
|
return;
|
|
1665
1680
|
}
|
|
1666
1681
|
}
|
|
@@ -1668,29 +1683,34 @@ export class Matterbridge extends EventEmitter {
|
|
|
1668
1683
|
if (plugin.type === 'AccessoryPlatform') {
|
|
1669
1684
|
try {
|
|
1670
1685
|
this.log.debug(`Creating endpoint ${dev}${device.deviceName}${db} for AccessoryPlatform plugin ${plg}${plugin.name}${db} server node`);
|
|
1686
|
+
if (plugin.serverNode) {
|
|
1687
|
+
this.log.error(`The plugin ${plg}${plugin.name}${er} has already added a device. Only one device is allowed per AccessoryPlatform plugin.`);
|
|
1688
|
+
return;
|
|
1689
|
+
}
|
|
1671
1690
|
await this.createAccessoryPlugin(plugin, device);
|
|
1672
1691
|
}
|
|
1673
1692
|
catch (error) {
|
|
1674
|
-
const errorMessage = error instanceof Error ? error.message :
|
|
1675
|
-
const
|
|
1676
|
-
|
|
1677
|
-
this.log.error(`Error creating endpoint ${dev}${device.deviceName}${er} (${zb}${device.id}${er}) for AccessoryPlatform plugin ${plg}${pluginName}${er} server node: ${error} ${errorMessage} ${errorStack} ${errorDebug}`);
|
|
1693
|
+
const errorMessage = error instanceof Error ? error.message : error;
|
|
1694
|
+
const errorInspect = inspect(error, { depth: 10 });
|
|
1695
|
+
this.log.error(`Error creating endpoint ${dev}${device.deviceName}${er} (${zb}${device.id}${er}) for AccessoryPlatform plugin ${plg}${pluginName}${er} server node: ${errorMessage}\nstack: ${errorInspect}`);
|
|
1678
1696
|
return;
|
|
1679
1697
|
}
|
|
1680
1698
|
}
|
|
1681
1699
|
if (plugin.type === 'DynamicPlatform') {
|
|
1682
|
-
plugin.locked = true;
|
|
1683
|
-
this.log.debug(`Adding bridged endpoint ${dev}${device.deviceName}${db} for DynamicPlatform plugin ${plg}${plugin.name}${db} aggregator node`);
|
|
1684
|
-
if (!plugin.aggregatorNode)
|
|
1685
|
-
this.log.error(`Aggregator node not found for plugin ${plg}${plugin.name}${db}`);
|
|
1686
1700
|
try {
|
|
1687
|
-
|
|
1701
|
+
this.log.debug(`Adding bridged endpoint ${dev}${device.deviceName}${db} for DynamicPlatform plugin ${plg}${plugin.name}${db} aggregator node`);
|
|
1702
|
+
await this.createDynamicPlugin(plugin);
|
|
1703
|
+
await waiter(`createDynamicPlugin(${plugin.name})`, () => plugin.serverNode?.hasParts === true);
|
|
1704
|
+
if (!plugin.aggregatorNode) {
|
|
1705
|
+
this.log.error(`Aggregator node not found for plugin ${plg}${plugin.name}${er}`);
|
|
1706
|
+
return;
|
|
1707
|
+
}
|
|
1708
|
+
await plugin.aggregatorNode.add(device);
|
|
1688
1709
|
}
|
|
1689
1710
|
catch (error) {
|
|
1690
|
-
const errorMessage = error instanceof Error ? error.message :
|
|
1691
|
-
const
|
|
1692
|
-
|
|
1693
|
-
this.log.error(`Error adding bridged endpoint ${dev}${device.deviceName}${er} (${zb}${device.id}${er}) for DynamicPlatform plugin ${plg}${pluginName}${er} aggregator node: ${error} ${errorMessage} ${errorStack} ${errorDebug}`);
|
|
1711
|
+
const errorMessage = error instanceof Error ? error.message : error;
|
|
1712
|
+
const errorInspect = inspect(error, { depth: 10 });
|
|
1713
|
+
this.log.error(`Error adding bridged endpoint ${dev}${device.deviceName}${er} (${zb}${device.id}${er}) for DynamicPlatform plugin ${plg}${pluginName}${er} aggregator node: ${errorMessage}\nstack: ${errorInspect}`);
|
|
1694
1714
|
return;
|
|
1695
1715
|
}
|
|
1696
1716
|
}
|
|
@@ -27,6 +27,7 @@ import { ElectricalEnergyMeasurement } from '@matter/main/clusters/electrical-en
|
|
|
27
27
|
import { AirQuality } from '@matter/main/clusters/air-quality';
|
|
28
28
|
import { ConcentrationMeasurement } from '@matter/main/clusters/concentration-measurement';
|
|
29
29
|
import { OccupancySensing } from '@matter/main/clusters/occupancy-sensing';
|
|
30
|
+
import { ThermostatUserInterfaceConfiguration } from '@matter/main/clusters/thermostat-user-interface-configuration';
|
|
30
31
|
import { DescriptorServer } from '@matter/main/behaviors/descriptor';
|
|
31
32
|
import { PowerSourceServer } from '@matter/main/behaviors/power-source';
|
|
32
33
|
import { BridgedDeviceBasicInformationServer } from '@matter/main/behaviors/bridged-device-basic-information';
|
|
@@ -59,6 +60,7 @@ import { FanControlServer } from '@matter/main/behaviors/fan-control';
|
|
|
59
60
|
import { ResourceMonitoring } from '@matter/main/clusters/resource-monitoring';
|
|
60
61
|
import { HepaFilterMonitoringServer } from '@matter/main/behaviors/hepa-filter-monitoring';
|
|
61
62
|
import { ActivatedCarbonFilterMonitoringServer } from '@matter/main/behaviors/activated-carbon-filter-monitoring';
|
|
63
|
+
import { ThermostatUserInterfaceConfigurationServer } from '@matter/main/behaviors/thermostat-user-interface-configuration';
|
|
62
64
|
export class MatterbridgeEndpoint extends Endpoint {
|
|
63
65
|
static bridgeMode = '';
|
|
64
66
|
static logLevel = "info";
|
|
@@ -760,6 +762,14 @@ export class MatterbridgeEndpoint extends Endpoint {
|
|
|
760
762
|
});
|
|
761
763
|
return this;
|
|
762
764
|
}
|
|
765
|
+
createDefaultThermostatUserInterfaceConfigurationClusterServer() {
|
|
766
|
+
this.behaviors.require(ThermostatUserInterfaceConfigurationServer, {
|
|
767
|
+
temperatureDisplayMode: ThermostatUserInterfaceConfiguration.TemperatureDisplayMode.Celsius,
|
|
768
|
+
keypadLockout: ThermostatUserInterfaceConfiguration.KeypadLockout.NoLockout,
|
|
769
|
+
scheduleProgrammingVisibility: ThermostatUserInterfaceConfiguration.ScheduleProgrammingVisibility.ScheduleProgrammingPermitted,
|
|
770
|
+
});
|
|
771
|
+
return this;
|
|
772
|
+
}
|
|
763
773
|
createDefaultFanControlClusterServer(fanMode = FanControl.FanMode.Off) {
|
|
764
774
|
this.behaviors.require(MatterbridgeFanControlServer.with(FanControl.Feature.MultiSpeed, FanControl.Feature.Auto, FanControl.Feature.Step), {
|
|
765
775
|
fanMode,
|
|
@@ -782,18 +792,24 @@ export class MatterbridgeEndpoint extends Endpoint {
|
|
|
782
792
|
return this;
|
|
783
793
|
}
|
|
784
794
|
createDefaultHepaFilterMonitoringClusterServer(changeIndication = ResourceMonitoring.ChangeIndication.Ok, inPlaceIndicator = undefined, lastChangedTime = undefined) {
|
|
785
|
-
this.behaviors.require(HepaFilterMonitoringServer, {
|
|
795
|
+
this.behaviors.require(HepaFilterMonitoringServer.with(ResourceMonitoring.Feature.Condition, ResourceMonitoring.Feature.ReplacementProductList), {
|
|
796
|
+
condition: 100,
|
|
797
|
+
degradationDirection: ResourceMonitoring.DegradationDirection.Down,
|
|
786
798
|
changeIndication,
|
|
787
799
|
inPlaceIndicator,
|
|
788
800
|
lastChangedTime,
|
|
801
|
+
replacementProductList: [],
|
|
789
802
|
});
|
|
790
803
|
return this;
|
|
791
804
|
}
|
|
792
805
|
createDefaultActivatedCarbonFilterMonitoringClusterServer(changeIndication = ResourceMonitoring.ChangeIndication.Ok, inPlaceIndicator = undefined, lastChangedTime = undefined) {
|
|
793
|
-
this.behaviors.require(ActivatedCarbonFilterMonitoringServer, {
|
|
806
|
+
this.behaviors.require(ActivatedCarbonFilterMonitoringServer.with(ResourceMonitoring.Feature.Condition, ResourceMonitoring.Feature.ReplacementProductList), {
|
|
807
|
+
condition: 100,
|
|
808
|
+
degradationDirection: ResourceMonitoring.DegradationDirection.Down,
|
|
794
809
|
changeIndication,
|
|
795
810
|
inPlaceIndicator,
|
|
796
811
|
lastChangedTime,
|
|
812
|
+
replacementProductList: [],
|
|
797
813
|
});
|
|
798
814
|
return this;
|
|
799
815
|
}
|
|
@@ -399,6 +399,20 @@ export function getAttributeId(endpoint, cluster, attribute) {
|
|
|
399
399
|
else if (attribute === 'levelValue')
|
|
400
400
|
return 0xa;
|
|
401
401
|
}
|
|
402
|
+
if (endpoint.behaviors.supported[lowercaseFirstLetter(cluster)]?.schema?.type === 'OperationalState') {
|
|
403
|
+
if (attribute === 'phaseList')
|
|
404
|
+
return 0x0;
|
|
405
|
+
else if (attribute === 'currentPhase')
|
|
406
|
+
return 0x1;
|
|
407
|
+
else if (attribute === 'countdownTime')
|
|
408
|
+
return 0x2;
|
|
409
|
+
else if (attribute === 'operationalStateList')
|
|
410
|
+
return 0x3;
|
|
411
|
+
else if (attribute === 'operationalState')
|
|
412
|
+
return 0x4;
|
|
413
|
+
else if (attribute === 'operationalError')
|
|
414
|
+
return 0x5;
|
|
415
|
+
}
|
|
402
416
|
return endpoint.behaviors.supported[lowercaseFirstLetter(cluster)]?.schema?.children?.find((child) => child.name === capitalizeFirstLetter(attribute))?.id;
|
|
403
417
|
}
|
|
404
418
|
}
|
|
@@ -84,8 +84,8 @@ export class MatterbridgePlatform {
|
|
|
84
84
|
async onChangeLoggerLevel(logLevel) {
|
|
85
85
|
this.log.debug(`The plugin doesn't override onChangeLoggerLevel. Logger level set to: ${logLevel}`);
|
|
86
86
|
}
|
|
87
|
-
async onAction(action, value, id) {
|
|
88
|
-
this.log.debug(`The plugin ${CYAN}${this.name}${db} doesn't override onAction. Received action ${CYAN}${action}${db}${value ? ' with ' + CYAN + value + db : ''} ${id ? ' for schema ' + CYAN + id + db : ''}
|
|
87
|
+
async onAction(action, value, id, formData) {
|
|
88
|
+
this.log.debug(`The plugin ${CYAN}${this.name}${db} doesn't override onAction. Received action ${CYAN}${action}${db}${value ? ' with ' + CYAN + value + db : ''} ${id ? ' for schema ' + CYAN + id + db : ''}`, formData);
|
|
89
89
|
}
|
|
90
90
|
async onConfigChanged(config) {
|
|
91
91
|
this.log.debug(`The plugin ${CYAN}${config.name}${db} doesn't override onConfigChanged. Received new config.`);
|
package/dist/update.js
CHANGED
|
@@ -3,6 +3,7 @@ import { db, nt, wr } from './logger/export.js';
|
|
|
3
3
|
export async function checkUpdates(matterbridge) {
|
|
4
4
|
const { hasParameter } = await import('./utils/parameter.js');
|
|
5
5
|
getMatterbridgeLatestVersion(matterbridge);
|
|
6
|
+
getMatterbridgeDevVersion(matterbridge);
|
|
6
7
|
for (const plugin of matterbridge.plugins) {
|
|
7
8
|
getPluginLatestVersion(matterbridge, plugin);
|
|
8
9
|
}
|
|
@@ -32,6 +33,23 @@ async function getMatterbridgeLatestVersion(matterbridge) {
|
|
|
32
33
|
matterbridge.log.warn(`Error getting Matterbridge latest version: ${error.message}`);
|
|
33
34
|
});
|
|
34
35
|
}
|
|
36
|
+
async function getMatterbridgeDevVersion(matterbridge) {
|
|
37
|
+
const { getNpmPackageVersion } = await import('./utils/network.js');
|
|
38
|
+
getNpmPackageVersion('matterbridge', 'dev')
|
|
39
|
+
.then(async (version) => {
|
|
40
|
+
matterbridge.matterbridgeDevVersion = version;
|
|
41
|
+
matterbridge.matterbridgeInformation.matterbridgeDevVersion = version;
|
|
42
|
+
await matterbridge.nodeContext?.set('matterbridgeDevVersion', version);
|
|
43
|
+
if (matterbridge.matterbridgeVersion.includes('-dev.') && matterbridge.matterbridgeVersion !== version) {
|
|
44
|
+
matterbridge.log.notice(`Matterbridge@dev is out of date. Current version: ${matterbridge.matterbridgeVersion}. Latest dev version: ${matterbridge.matterbridgeDevVersion}.`);
|
|
45
|
+
matterbridge.frontend.wssSendRefreshRequired('matterbridgeDevVersion');
|
|
46
|
+
matterbridge.frontend.wssSendUpdateRequired();
|
|
47
|
+
}
|
|
48
|
+
})
|
|
49
|
+
.catch((error) => {
|
|
50
|
+
matterbridge.log.warn(`Error getting Matterbridge latest dev version: ${error.message}`);
|
|
51
|
+
});
|
|
52
|
+
}
|
|
35
53
|
async function getPluginLatestVersion(matterbridge, plugin) {
|
|
36
54
|
const { getNpmPackageVersion } = await import('./utils/network.js');
|
|
37
55
|
getNpmPackageVersion(plugin.name)
|
package/dist/utils/parameter.js
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
export function hasParameter(name) {
|
|
2
|
+
const commandArguments = process.argv.slice(2);
|
|
3
|
+
let markerIncluded = commandArguments.includes(`-${name}`);
|
|
4
|
+
if (!markerIncluded)
|
|
5
|
+
markerIncluded = commandArguments.includes(`--${name}`);
|
|
6
|
+
return markerIncluded;
|
|
7
|
+
}
|
|
1
8
|
import { isValidNumber } from './export.js';
|
|
2
9
|
export function getParameter(name) {
|
|
3
10
|
const commandArguments = process.argv.slice(2);
|
|
@@ -8,13 +15,6 @@ export function getParameter(name) {
|
|
|
8
15
|
return undefined;
|
|
9
16
|
return commandArguments[markerIndex + 1];
|
|
10
17
|
}
|
|
11
|
-
export function hasParameter(name) {
|
|
12
|
-
const commandArguments = process.argv.slice(2);
|
|
13
|
-
let markerIncluded = commandArguments.includes(`-${name}`);
|
|
14
|
-
if (!markerIncluded)
|
|
15
|
-
markerIncluded = commandArguments.includes(`--${name}`);
|
|
16
|
-
return markerIncluded;
|
|
17
|
-
}
|
|
18
18
|
export function getIntParameter(name) {
|
|
19
19
|
const value = getParameter(name);
|
|
20
20
|
if (value === undefined)
|
|
@@ -24,3 +24,35 @@ export function getIntParameter(name) {
|
|
|
24
24
|
return undefined;
|
|
25
25
|
return intValue;
|
|
26
26
|
}
|
|
27
|
+
export function getIntArrayParameter(name) {
|
|
28
|
+
const commandArguments = process.argv.slice(2);
|
|
29
|
+
let markerIndex = commandArguments.indexOf(`--${name}`);
|
|
30
|
+
if (markerIndex < 0)
|
|
31
|
+
markerIndex = commandArguments.indexOf(`-${name}`);
|
|
32
|
+
if (markerIndex < 0)
|
|
33
|
+
return undefined;
|
|
34
|
+
const intValues = [];
|
|
35
|
+
for (let i = markerIndex + 1; i < commandArguments.length && !commandArguments[i].startsWith('-'); i++) {
|
|
36
|
+
const intValue = parseInt(commandArguments[i], 10);
|
|
37
|
+
if (isValidNumber(intValue))
|
|
38
|
+
intValues.push(intValue);
|
|
39
|
+
}
|
|
40
|
+
if (intValues.length === 0)
|
|
41
|
+
return undefined;
|
|
42
|
+
return intValues;
|
|
43
|
+
}
|
|
44
|
+
export function getStringArrayParameter(name) {
|
|
45
|
+
const commandArguments = process.argv.slice(2);
|
|
46
|
+
let markerIndex = commandArguments.indexOf(`--${name}`);
|
|
47
|
+
if (markerIndex < 0)
|
|
48
|
+
markerIndex = commandArguments.indexOf(`-${name}`);
|
|
49
|
+
if (markerIndex < 0)
|
|
50
|
+
return undefined;
|
|
51
|
+
const values = [];
|
|
52
|
+
for (let i = markerIndex + 1; i < commandArguments.length && !commandArguments[i].startsWith('-'); i++) {
|
|
53
|
+
values.push(commandArguments[i]);
|
|
54
|
+
}
|
|
55
|
+
if (values.length === 0)
|
|
56
|
+
return undefined;
|
|
57
|
+
return values;
|
|
58
|
+
}
|
package/dist/utils/wait.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { AnsiLogger } from '../logger/export.js';
|
|
2
2
|
const log = new AnsiLogger({ logName: 'MatterbridgeUtils', logTimestampFormat: 4, logLevel: "info" });
|
|
3
3
|
export async function waiter(name, check, exitWithReject = false, resolveTimeout = 5000, resolveInterval = 500, debug = false) {
|
|
4
|
+
if (check())
|
|
5
|
+
return true;
|
|
4
6
|
log.logLevel = "debug";
|
|
5
7
|
log.logName = 'Waiter';
|
|
6
8
|
if (debug)
|