matterbridge 2.1.6-dev.4 → 2.1.6-dev.6
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 +8 -6
- package/README-DEV.md +1 -1
- package/README-DOCKER.md +1 -1
- package/README-EDGE.md +1 -1
- package/README-NGINX.md +1 -1
- package/README-PODMAN.md +1 -1
- package/README-SERVICE.md +1 -1
- package/README.md +18 -18
- package/dist/cli.js +91 -89
- package/dist/frontend.js +20 -6
- package/dist/index.js +6 -8
- package/dist/matterbridge.js +55 -64
- package/dist/matterbridgeEndpoint.js +1 -1
- package/dist/matterbridgeEndpointHelpers.js +2 -2
- package/dist/matterbridgePlatform.js +2 -2
- package/dist/utils/colorUtils.js +1 -1
- package/dist/utils/export.js +2 -0
- package/dist/utils/isvalid.js +50 -0
- package/dist/utils/parameter.js +26 -0
- package/dist/utils/utils.js +19 -81
- package/frontend/build/asset-manifest.json +3 -3
- package/frontend/build/index.html +1 -1
- package/frontend/build/static/js/{main.257513e8.js → main.438c6c47.js} +9 -9
- package/frontend/build/static/js/main.438c6c47.js.map +1 -0
- package/npm-shrinkwrap.json +50 -50
- package/package.json +2 -2
- package/frontend/build/static/js/main.257513e8.js.map +0 -1
- /package/frontend/build/static/js/{main.257513e8.js.LICENSE.txt → main.438c6c47.js.LICENSE.txt} +0 -0
package/dist/matterbridge.js
CHANGED
|
@@ -1,13 +1,11 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import EventEmitter from 'events';
|
|
5
|
-
import os from 'os';
|
|
6
|
-
import path from 'path';
|
|
7
|
-
import { randomBytes } from 'crypto';
|
|
8
|
-
import { NodeStorageManager } from './storage/export.js';
|
|
1
|
+
import os from 'node:os';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { promises as fs } from 'node:fs';
|
|
4
|
+
import EventEmitter from 'node:events';
|
|
9
5
|
import { AnsiLogger, UNDERLINE, UNDERLINEOFF, YELLOW, db, debugStringify, BRIGHT, RESET, er, nf, rs, wr, RED, GREEN, zb, CYAN, nt } from './logger/export.js';
|
|
10
|
-
import {
|
|
6
|
+
import { NodeStorageManager } from './storage/export.js';
|
|
7
|
+
import { getParameter, getIntParameter, hasParameter } from './utils/export.js';
|
|
8
|
+
import { logInterfaces, copyDirectory, getNpmPackageVersion, getGlobalNodeModules } from './utils/utils.js';
|
|
11
9
|
import { PluginManager } from './pluginManager.js';
|
|
12
10
|
import { DeviceManager } from './deviceManager.js';
|
|
13
11
|
import { MatterbridgeEndpoint } from './matterbridgeEndpoint.js';
|
|
@@ -54,6 +52,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
54
52
|
matterbridgeFabricInformations: [],
|
|
55
53
|
matterbridgeSessionInformations: [],
|
|
56
54
|
matterbridgePaired: false,
|
|
55
|
+
matterbridgeAdvertise: false,
|
|
57
56
|
bridgeMode: '',
|
|
58
57
|
restartMode: '',
|
|
59
58
|
readOnly: hasParameter('readonly'),
|
|
@@ -86,6 +85,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
86
85
|
bridgeMode = '';
|
|
87
86
|
restartMode = '';
|
|
88
87
|
profile = getParameter('profile');
|
|
88
|
+
shutdown = false;
|
|
89
89
|
edge = true;
|
|
90
90
|
log;
|
|
91
91
|
matterbrideLoggerFile = 'matterbridge' + (getParameter('profile') ? '.' + getParameter('profile') : '') + '.log';
|
|
@@ -174,6 +174,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
174
174
|
return Matterbridge.instance;
|
|
175
175
|
}
|
|
176
176
|
async destroyInstance() {
|
|
177
|
+
this.log.info(`Destroy instance...`);
|
|
177
178
|
const servers = [];
|
|
178
179
|
if (this.bridgeMode === 'bridge') {
|
|
179
180
|
if (this.serverNode)
|
|
@@ -186,6 +187,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
186
187
|
}
|
|
187
188
|
}
|
|
188
189
|
await this.cleanup('destroying instance...', false);
|
|
190
|
+
this.log.info(`Dispose ${servers.length} MdnsService...`);
|
|
189
191
|
for (const server of servers) {
|
|
190
192
|
await server.env.get(MdnsService)[Symbol.asyncDispose]();
|
|
191
193
|
this.log.info(`Closed ${server.id} MdnsService`);
|
|
@@ -250,7 +252,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
250
252
|
this.port = getIntParameter('port') ?? (await this.nodeContext.get('matterport', 5540)) ?? 5540;
|
|
251
253
|
this.passcode = getIntParameter('passcode') ?? (await this.nodeContext.get('matterpasscode')) ?? PaseClient.generateRandomPasscode();
|
|
252
254
|
this.discriminator = getIntParameter('discriminator') ?? (await this.nodeContext.get('matterdiscriminator')) ?? PaseClient.generateRandomDiscriminator();
|
|
253
|
-
this.log.debug(`Initializing
|
|
255
|
+
this.log.debug(`Initializing server node for Matterbridge... on port ${this.port} with passcode ${this.passcode} and discriminator ${this.discriminator}`);
|
|
254
256
|
if (hasParameter('logger')) {
|
|
255
257
|
const level = getParameter('logger');
|
|
256
258
|
if (level === 'debug') {
|
|
@@ -288,6 +290,8 @@ export class Matterbridge extends EventEmitter {
|
|
|
288
290
|
}
|
|
289
291
|
this.log.notice('Matterbridge is starting...');
|
|
290
292
|
this.log.debug(`Matterbridge logLevel: ${this.log.logLevel} fileLoger: ${this.matterbridgeInformation.fileLogger}.`);
|
|
293
|
+
if (this.profile !== undefined)
|
|
294
|
+
this.log.debug(`Matterbridge profile: ${this.profile}.`);
|
|
291
295
|
if (hasParameter('matterlogger')) {
|
|
292
296
|
const level = getParameter('matterlogger');
|
|
293
297
|
if (level === 'debug') {
|
|
@@ -443,7 +447,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
443
447
|
- disable [plugin name]: disable the globally installed plugin with the given name
|
|
444
448
|
- reset [plugin path]: remove the commissioning for the plugin from the given absolute or relative path (childbridge mode). Shutdown Matterbridge before using it!
|
|
445
449
|
- reset [plugin name]: remove the commissioning for the globally installed plugin (childbridge mode). Shutdown Matterbridge before using it!${rs}`);
|
|
446
|
-
this.
|
|
450
|
+
this.shutdown = true;
|
|
447
451
|
return;
|
|
448
452
|
}
|
|
449
453
|
if (hasParameter('list')) {
|
|
@@ -472,7 +476,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
472
476
|
this.log.info(` └─ endpoint ${RED}${device.endpoint}${nf} ${typ}${device.endpointName}${nf} ${debugStringify(device.clusterServersId)}`);
|
|
473
477
|
}
|
|
474
478
|
});
|
|
475
|
-
this.
|
|
479
|
+
this.shutdown = true;
|
|
476
480
|
return;
|
|
477
481
|
}
|
|
478
482
|
if (hasParameter('logstorage')) {
|
|
@@ -482,41 +486,43 @@ export class Matterbridge extends EventEmitter {
|
|
|
482
486
|
this.log.info(`${plg}${plugin.name}${nf} storage log`);
|
|
483
487
|
await plugin.nodeContext?.logStorage();
|
|
484
488
|
}
|
|
485
|
-
this.
|
|
489
|
+
this.shutdown = true;
|
|
486
490
|
return;
|
|
487
491
|
}
|
|
488
492
|
if (hasParameter('loginterfaces')) {
|
|
489
493
|
this.log.info(`${plg}Matterbridge${nf} network interfaces log`);
|
|
490
494
|
logInterfaces();
|
|
491
|
-
this.
|
|
495
|
+
this.shutdown = true;
|
|
492
496
|
return;
|
|
493
497
|
}
|
|
494
498
|
if (getParameter('add')) {
|
|
495
499
|
this.log.debug(`Adding plugin ${getParameter('add')}`);
|
|
496
500
|
await this.plugins.add(getParameter('add'));
|
|
497
|
-
this.
|
|
501
|
+
this.shutdown = true;
|
|
498
502
|
return;
|
|
499
503
|
}
|
|
500
504
|
if (getParameter('remove')) {
|
|
501
505
|
this.log.debug(`Removing plugin ${getParameter('remove')}`);
|
|
502
506
|
await this.plugins.remove(getParameter('remove'));
|
|
503
|
-
this.
|
|
507
|
+
this.shutdown = true;
|
|
504
508
|
return;
|
|
505
509
|
}
|
|
506
510
|
if (getParameter('enable')) {
|
|
507
511
|
this.log.debug(`Enabling plugin ${getParameter('enable')}`);
|
|
508
512
|
await this.plugins.enable(getParameter('enable'));
|
|
509
|
-
this.
|
|
513
|
+
this.shutdown = true;
|
|
510
514
|
return;
|
|
511
515
|
}
|
|
512
516
|
if (getParameter('disable')) {
|
|
513
517
|
this.log.debug(`Disabling plugin ${getParameter('disable')}`);
|
|
514
518
|
await this.plugins.disable(getParameter('disable'));
|
|
515
|
-
this.
|
|
519
|
+
this.shutdown = true;
|
|
516
520
|
return;
|
|
517
521
|
}
|
|
518
522
|
if (hasParameter('factoryreset')) {
|
|
523
|
+
this.initialized = true;
|
|
519
524
|
await this.shutdownProcessAndFactoryReset();
|
|
525
|
+
this.shutdown = true;
|
|
520
526
|
return;
|
|
521
527
|
}
|
|
522
528
|
try {
|
|
@@ -527,7 +533,9 @@ export class Matterbridge extends EventEmitter {
|
|
|
527
533
|
throw new Error(`Fatal error creating matter storage: ${error instanceof Error ? error.message : error}`);
|
|
528
534
|
}
|
|
529
535
|
if (hasParameter('reset') && getParameter('reset') === undefined) {
|
|
536
|
+
this.initialized = true;
|
|
530
537
|
await this.shutdownProcessAndReset();
|
|
538
|
+
this.shutdown = true;
|
|
531
539
|
return;
|
|
532
540
|
}
|
|
533
541
|
if (hasParameter('reset') && getParameter('reset') !== undefined) {
|
|
@@ -535,20 +543,23 @@ export class Matterbridge extends EventEmitter {
|
|
|
535
543
|
const plugin = this.plugins.get(getParameter('reset'));
|
|
536
544
|
if (plugin) {
|
|
537
545
|
const matterStorageManager = await this.matterStorageService?.open(plugin.name);
|
|
538
|
-
if (!matterStorageManager)
|
|
546
|
+
if (!matterStorageManager) {
|
|
539
547
|
this.log.error(`Plugin ${plg}${plugin.name}${er} storageManager not found`);
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
548
|
+
}
|
|
549
|
+
else {
|
|
550
|
+
await matterStorageManager?.createContext('events')?.clearAll();
|
|
551
|
+
await matterStorageManager?.createContext('fabrics')?.clearAll();
|
|
552
|
+
await matterStorageManager?.createContext('root')?.clearAll();
|
|
553
|
+
await matterStorageManager?.createContext('sessions')?.clearAll();
|
|
554
|
+
await matterStorageManager?.createContext('persist')?.clearAll();
|
|
555
|
+
this.log.info(`Reset commissionig for plugin ${plg}${plugin.name}${nf} done! Remove the device from the controller.`);
|
|
556
|
+
}
|
|
546
557
|
}
|
|
547
558
|
else {
|
|
548
559
|
this.log.warn(`Plugin ${plg}${getParameter('reset')}${wr} not registerd in matterbridge`);
|
|
549
560
|
}
|
|
550
561
|
await this.stopMatterStorage();
|
|
551
|
-
this.
|
|
562
|
+
this.shutdown = true;
|
|
552
563
|
return;
|
|
553
564
|
}
|
|
554
565
|
if (getIntParameter('frontend') !== 0 || getIntParameter('frontend') === undefined)
|
|
@@ -720,6 +731,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
720
731
|
this.homeDirectory = getParameter('homedir') ?? os.homedir();
|
|
721
732
|
this.matterbridgeInformation.homeDirectory = this.homeDirectory;
|
|
722
733
|
this.log.debug(`Home Directory: ${this.homeDirectory}`);
|
|
734
|
+
const { fileURLToPath } = await import('node:url');
|
|
723
735
|
const currentFileDirectory = path.dirname(fileURLToPath(import.meta.url));
|
|
724
736
|
this.rootDirectory = path.resolve(currentFileDirectory, '../');
|
|
725
737
|
this.matterbridgeInformation.rootDirectory = this.rootDirectory;
|
|
@@ -728,7 +740,9 @@ export class Matterbridge extends EventEmitter {
|
|
|
728
740
|
this.globalModulesDirectory = this.matterbridgeInformation.globalModulesDirectory = await this.nodeContext.get('globalModulesDirectory', '');
|
|
729
741
|
if (this.globalModulesDirectory === '') {
|
|
730
742
|
try {
|
|
731
|
-
this.
|
|
743
|
+
this.execRunningCount++;
|
|
744
|
+
this.globalModulesDirectory = await getGlobalNodeModules();
|
|
745
|
+
this.execRunningCount--;
|
|
732
746
|
this.matterbridgeInformation.globalModulesDirectory = this.globalModulesDirectory;
|
|
733
747
|
this.log.debug(`Global node_modules Directory: ${this.globalModulesDirectory}`);
|
|
734
748
|
await this.nodeContext?.set('globalModulesDirectory', this.globalModulesDirectory);
|
|
@@ -797,20 +811,6 @@ export class Matterbridge extends EventEmitter {
|
|
|
797
811
|
const cmdArgs = process.argv.slice(2).join(' ');
|
|
798
812
|
this.log.debug(`Command Line Arguments: ${cmdArgs}`);
|
|
799
813
|
}
|
|
800
|
-
async getGlobalNodeModules() {
|
|
801
|
-
return new Promise((resolve, reject) => {
|
|
802
|
-
this.execRunningCount++;
|
|
803
|
-
exec('npm root -g', (error, stdout) => {
|
|
804
|
-
this.execRunningCount--;
|
|
805
|
-
if (error) {
|
|
806
|
-
reject(error);
|
|
807
|
-
}
|
|
808
|
-
else {
|
|
809
|
-
resolve(stdout.trim());
|
|
810
|
-
}
|
|
811
|
-
});
|
|
812
|
-
});
|
|
813
|
-
}
|
|
814
814
|
async getMatterbridgeLatestVersion() {
|
|
815
815
|
getNpmPackageVersion('matterbridge')
|
|
816
816
|
.then(async (version) => {
|
|
@@ -1202,11 +1202,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
1202
1202
|
if (!plugin.enabled)
|
|
1203
1203
|
continue;
|
|
1204
1204
|
if (plugin.type === 'DynamicPlatform') {
|
|
1205
|
-
plugin
|
|
1206
|
-
plugin.storageContext = await this.createServerNodeContext(plugin.name, 'Matterbridge', bridge.code, this.aggregatorVendorId, 'Matterbridge', this.aggregatorProductId, plugin.description);
|
|
1207
|
-
plugin.serverNode = await this.createServerNode(plugin.storageContext, this.port ? this.port++ : undefined, this.passcode ? this.passcode++ : undefined, this.discriminator ? this.discriminator++ : undefined);
|
|
1208
|
-
plugin.aggregatorNode = await this.createAggregatorNode(plugin.storageContext);
|
|
1209
|
-
await plugin.serverNode.add(plugin.aggregatorNode);
|
|
1205
|
+
await this.createDynamicPlugin(plugin);
|
|
1210
1206
|
}
|
|
1211
1207
|
}
|
|
1212
1208
|
await this.startPlugins();
|
|
@@ -1259,7 +1255,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
1259
1255
|
for (const plugin of this.plugins) {
|
|
1260
1256
|
if (!plugin.enabled || plugin.error)
|
|
1261
1257
|
continue;
|
|
1262
|
-
if (!plugin.addedDevices || plugin.addedDevices === 0) {
|
|
1258
|
+
if (plugin.type !== 'DynamicPlatform' && (!plugin.addedDevices || plugin.addedDevices === 0)) {
|
|
1263
1259
|
this.log.error(`Plugin ${plg}${plugin.name}${er} didn't add any devices to Matterbridge. Verify the plugin configuration.`);
|
|
1264
1260
|
continue;
|
|
1265
1261
|
}
|
|
@@ -1315,6 +1311,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
1315
1311
|
this.log.info('Matter node storage closed');
|
|
1316
1312
|
}
|
|
1317
1313
|
async createServerNodeContext(pluginName, deviceName, deviceType, vendorId, vendorName, productId, productName, serialNumber) {
|
|
1314
|
+
const { randomBytes } = await import('node:crypto');
|
|
1318
1315
|
if (!this.matterStorageService)
|
|
1319
1316
|
throw new Error('No storage service initialized');
|
|
1320
1317
|
this.log.info(`Creating server node storage context "${pluginName}.persist" for ${pluginName}...`);
|
|
@@ -1557,13 +1554,18 @@ export class Matterbridge extends EventEmitter {
|
|
|
1557
1554
|
}
|
|
1558
1555
|
}
|
|
1559
1556
|
async advertiseServerNode(matterServerNode) {
|
|
1560
|
-
if (matterServerNode
|
|
1557
|
+
if (matterServerNode) {
|
|
1561
1558
|
await matterServerNode.env.get(DeviceCommissioner)?.allowBasicCommissioning();
|
|
1562
1559
|
const { qrPairingCode, manualPairingCode } = matterServerNode.state.commissioning.pairingCodes;
|
|
1563
|
-
this.log.notice(`
|
|
1560
|
+
this.log.notice(`Started advertising for ${matterServerNode.id} with the following pairing codes: qrPairingCode ${qrPairingCode}, manualPairingCode ${manualPairingCode}`);
|
|
1564
1561
|
return { qrPairingCode, manualPairingCode };
|
|
1565
1562
|
}
|
|
1566
|
-
|
|
1563
|
+
}
|
|
1564
|
+
async stopAdvertiseServerNode(matterServerNode) {
|
|
1565
|
+
if (matterServerNode && matterServerNode.lifecycle.isOnline) {
|
|
1566
|
+
await matterServerNode.env.get(DeviceCommissioner)?.endCommissioning();
|
|
1567
|
+
this.log.notice(`Stopped advertising for ${matterServerNode.id}`);
|
|
1568
|
+
}
|
|
1567
1569
|
}
|
|
1568
1570
|
async createAggregatorNode(storageContext) {
|
|
1569
1571
|
this.log.notice(`Creating ${await storageContext.get('storeId')} aggregator `);
|
|
@@ -1635,15 +1637,6 @@ export class Matterbridge extends EventEmitter {
|
|
|
1635
1637
|
plugin.registeredDevices--;
|
|
1636
1638
|
if (plugin.addedDevices !== undefined)
|
|
1637
1639
|
plugin.addedDevices--;
|
|
1638
|
-
if (plugin.registeredDevices === 0 && plugin.addedDevices === 0) {
|
|
1639
|
-
if (plugin.serverNode) {
|
|
1640
|
-
await this.stopServerNode(plugin.serverNode);
|
|
1641
|
-
plugin.locked = false;
|
|
1642
|
-
plugin.aggregatorNode = undefined;
|
|
1643
|
-
plugin.serverNode = undefined;
|
|
1644
|
-
this.log.info(`Stopped server node for plugin ${plg}${pluginName}${nf}`);
|
|
1645
|
-
}
|
|
1646
|
-
}
|
|
1647
1640
|
}
|
|
1648
1641
|
this.devices.remove(device);
|
|
1649
1642
|
}
|
|
@@ -1702,7 +1695,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
1702
1695
|
getVendorIdName = (vendorId) => {
|
|
1703
1696
|
if (!vendorId)
|
|
1704
1697
|
return '';
|
|
1705
|
-
let vendorName = '';
|
|
1698
|
+
let vendorName = '(Unknown vendorId)';
|
|
1706
1699
|
switch (vendorId) {
|
|
1707
1700
|
case 4937:
|
|
1708
1701
|
vendorName = '(AppleHome)';
|
|
@@ -1732,15 +1725,13 @@ export class Matterbridge extends EventEmitter {
|
|
|
1732
1725
|
vendorName = '(eWeLink)';
|
|
1733
1726
|
break;
|
|
1734
1727
|
case 65521:
|
|
1735
|
-
vendorName = '(
|
|
1736
|
-
break;
|
|
1737
|
-
default:
|
|
1738
|
-
vendorName = '(unknown)';
|
|
1728
|
+
vendorName = '(MatterServer)';
|
|
1739
1729
|
break;
|
|
1740
1730
|
}
|
|
1741
1731
|
return vendorName;
|
|
1742
1732
|
};
|
|
1743
1733
|
async spawnCommand(command, args = []) {
|
|
1734
|
+
const { spawn } = await import('node:child_process');
|
|
1744
1735
|
const cmdLine = command + ' ' + args.join(' ');
|
|
1745
1736
|
if (process.platform === 'win32' && command === 'npm') {
|
|
1746
1737
|
const argstring = 'npm ' + args.join(' ');
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AnsiLogger, BLUE, CYAN, YELLOW, db, debugStringify, er, hk, or, zb } from './logger/export.js';
|
|
2
2
|
import { bridgedNode } from './matterbridgeDeviceTypes.js';
|
|
3
|
-
import { isValidNumber, isValidObject } from './utils/
|
|
3
|
+
import { isValidNumber, isValidObject } from './utils/export.js';
|
|
4
4
|
import { MatterbridgeBehavior, MatterbridgeBehaviorDevice, MatterbridgeIdentifyServer, MatterbridgeOnOffServer, MatterbridgeLevelControlServer, MatterbridgeColorControlServer, MatterbridgeWindowCoveringServer, MatterbridgeThermostatServer, MatterbridgeFanControlServer, MatterbridgeDoorLockServer, MatterbridgeModeSelectServer, MatterbridgeValveConfigurationAndControlServer, MatterbridgeSmokeCoAlarmServer, MatterbridgeBooleanStateConfigurationServer, MatterbridgeSwitchServer, } from './matterbridgeBehaviors.js';
|
|
5
5
|
import { addClusterServers, addFixedLabel, addOptionalClusterServers, addRequiredClusterServers, addUserLabel, capitalizeFirstLetter, createUniqueId, getBehavior, getBehaviourTypesFromClusterClientIds, getBehaviourTypesFromClusterServerIds, getDefaultFlowMeasurementClusterServer, getDefaultIlluminanceMeasurementClusterServer, getDefaultPressureMeasurementClusterServer, getDefaultRelativeHumidityMeasurementClusterServer, getDefaultTemperatureMeasurementClusterServer, getDefaultOccupancySensingClusterServer, lowercaseFirstLetter, updateAttribute, getClusterId, getAttributeId, setAttribute, getAttribute, checkNotLatinCharacters, generateUniqueId, subscribeAttribute, } from './matterbridgeEndpointHelpers.js';
|
|
6
6
|
import { Endpoint, Lifecycle, MutableEndpoint, NamedHandler, SupportedBehaviors, VendorId } from '@matter/main';
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { createHash } from 'crypto';
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
2
|
import { BLUE, CYAN, db, debugStringify, er, hk, or, YELLOW, zb } from './logger/export.js';
|
|
3
|
+
import { deepCopy, deepEqual, isValidArray } from './utils/export.js';
|
|
3
4
|
import { MatterbridgeIdentifyServer, MatterbridgeOnOffServer, MatterbridgeLevelControlServer, MatterbridgeColorControlServer, MatterbridgeWindowCoveringServer, MatterbridgeThermostatServer, MatterbridgeFanControlServer, MatterbridgeDoorLockServer, MatterbridgeModeSelectServer, MatterbridgeValveConfigurationAndControlServer, MatterbridgeSmokeCoAlarmServer, MatterbridgeBooleanStateConfigurationServer, } from './matterbridgeBehaviors.js';
|
|
4
5
|
import { Lifecycle } from '@matter/main';
|
|
5
6
|
import { getClusterNameById } from '@matter/main/types';
|
|
@@ -73,7 +74,6 @@ import { Pm25ConcentrationMeasurementServer } from '@matter/main/behaviors/pm25-
|
|
|
73
74
|
import { Pm10ConcentrationMeasurementServer } from '@matter/main/behaviors/pm10-concentration-measurement';
|
|
74
75
|
import { RadonConcentrationMeasurementServer } from '@matter/main/behaviors/radon-concentration-measurement';
|
|
75
76
|
import { TotalVolatileOrganicCompoundsConcentrationMeasurementServer } from '@matter/main/behaviors/total-volatile-organic-compounds-concentration-measurement';
|
|
76
|
-
import { deepCopy, deepEqual, isValidArray } from './utils/utils.js';
|
|
77
77
|
export function capitalizeFirstLetter(name) {
|
|
78
78
|
if (!name)
|
|
79
79
|
return name;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { checkNotLatinCharacters } from './matterbridgeEndpointHelpers.js';
|
|
2
|
-
import { isValidArray, isValidObject, isValidString } from './utils/
|
|
2
|
+
import { isValidArray, isValidObject, isValidString } from './utils/export.js';
|
|
3
3
|
import { CYAN, db, er, nf, wr } from './logger/export.js';
|
|
4
4
|
import { NodeStorageManager } from './storage/export.js';
|
|
5
|
-
import path from 'path';
|
|
5
|
+
import path from 'node:path';
|
|
6
6
|
export class MatterbridgePlatform {
|
|
7
7
|
matterbridge;
|
|
8
8
|
log;
|
package/dist/utils/colorUtils.js
CHANGED
package/dist/utils/export.js
CHANGED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
export function isValidIpv4Address(ipv4Address) {
|
|
2
|
+
const ipv4Regex = /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
|
|
3
|
+
return ipv4Regex.test(ipv4Address);
|
|
4
|
+
}
|
|
5
|
+
export function isValidNumber(value, min, max) {
|
|
6
|
+
if (value === undefined || value === null || typeof value !== 'number' || Number.isNaN(value))
|
|
7
|
+
return false;
|
|
8
|
+
if (min !== undefined && value < min)
|
|
9
|
+
return false;
|
|
10
|
+
if (max !== undefined && value > max)
|
|
11
|
+
return false;
|
|
12
|
+
return true;
|
|
13
|
+
}
|
|
14
|
+
export function isValidBoolean(value) {
|
|
15
|
+
return value !== undefined && value !== null && typeof value === 'boolean';
|
|
16
|
+
}
|
|
17
|
+
export function isValidString(value, minLength, maxLength) {
|
|
18
|
+
if (value === undefined || value === null || typeof value !== 'string')
|
|
19
|
+
return false;
|
|
20
|
+
if (minLength !== undefined && value.length < minLength)
|
|
21
|
+
return false;
|
|
22
|
+
if (maxLength !== undefined && value.length > maxLength)
|
|
23
|
+
return false;
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
export function isValidObject(value, minLength, maxLength) {
|
|
27
|
+
if (value === undefined || value === null || typeof value !== 'object' || Array.isArray(value))
|
|
28
|
+
return false;
|
|
29
|
+
const keys = Object.keys(value);
|
|
30
|
+
if (minLength !== undefined && keys.length < minLength)
|
|
31
|
+
return false;
|
|
32
|
+
if (maxLength !== undefined && keys.length > maxLength)
|
|
33
|
+
return false;
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
export function isValidArray(value, minLength, maxLength) {
|
|
37
|
+
if (value === undefined || value === null || !Array.isArray(value))
|
|
38
|
+
return false;
|
|
39
|
+
if (minLength !== undefined && value.length < minLength)
|
|
40
|
+
return false;
|
|
41
|
+
if (maxLength !== undefined && value.length > maxLength)
|
|
42
|
+
return false;
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
export function isValidNull(value) {
|
|
46
|
+
return value === null;
|
|
47
|
+
}
|
|
48
|
+
export function isValidUndefined(value) {
|
|
49
|
+
return value === undefined;
|
|
50
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { isValidNumber } from './export.js';
|
|
2
|
+
export function getParameter(name) {
|
|
3
|
+
const commandArguments = process.argv.slice(2);
|
|
4
|
+
let markerIndex = commandArguments.indexOf(`-${name}`);
|
|
5
|
+
if (markerIndex === -1)
|
|
6
|
+
markerIndex = commandArguments.indexOf(`--${name}`);
|
|
7
|
+
if (markerIndex === -1 || markerIndex + 1 === commandArguments.length)
|
|
8
|
+
return undefined;
|
|
9
|
+
return commandArguments[markerIndex + 1];
|
|
10
|
+
}
|
|
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
|
+
export function getIntParameter(name) {
|
|
19
|
+
const value = getParameter(name);
|
|
20
|
+
if (value === undefined)
|
|
21
|
+
return undefined;
|
|
22
|
+
const intValue = parseInt(value, 10);
|
|
23
|
+
if (!isValidNumber(intValue))
|
|
24
|
+
return undefined;
|
|
25
|
+
return intValue;
|
|
26
|
+
}
|
package/dist/utils/utils.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import os from 'os';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
import { AnsiLogger, idn, rs } from '
|
|
1
|
+
import os from 'node:os';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { AnsiLogger, idn, rs } from '../logger/export.js';
|
|
4
4
|
const log = new AnsiLogger({ logName: 'MatterbridgeUtils', logTimestampFormat: 4, logLevel: "info" });
|
|
5
5
|
export function deepEqual(a, b, excludeProperties = []) {
|
|
6
6
|
const debug = false;
|
|
@@ -147,56 +147,6 @@ export function getMacAddress() {
|
|
|
147
147
|
}
|
|
148
148
|
return macAddress;
|
|
149
149
|
}
|
|
150
|
-
export function isValidIpv4Address(ipv4Address) {
|
|
151
|
-
const ipv4Regex = /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
|
|
152
|
-
return ipv4Regex.test(ipv4Address);
|
|
153
|
-
}
|
|
154
|
-
export function isValidNumber(value, min, max) {
|
|
155
|
-
if (value === undefined || value === null || typeof value !== 'number' || Number.isNaN(value))
|
|
156
|
-
return false;
|
|
157
|
-
if (min !== undefined && value < min)
|
|
158
|
-
return false;
|
|
159
|
-
if (max !== undefined && value > max)
|
|
160
|
-
return false;
|
|
161
|
-
return true;
|
|
162
|
-
}
|
|
163
|
-
export function isValidBoolean(value) {
|
|
164
|
-
return value !== undefined && value !== null && typeof value === 'boolean';
|
|
165
|
-
}
|
|
166
|
-
export function isValidString(value, minLength, maxLength) {
|
|
167
|
-
if (value === undefined || value === null || typeof value !== 'string')
|
|
168
|
-
return false;
|
|
169
|
-
if (minLength !== undefined && value.length < minLength)
|
|
170
|
-
return false;
|
|
171
|
-
if (maxLength !== undefined && value.length > maxLength)
|
|
172
|
-
return false;
|
|
173
|
-
return true;
|
|
174
|
-
}
|
|
175
|
-
export function isValidObject(value, minLength, maxLength) {
|
|
176
|
-
if (value === undefined || value === null || typeof value !== 'object' || Array.isArray(value))
|
|
177
|
-
return false;
|
|
178
|
-
const keys = Object.keys(value);
|
|
179
|
-
if (minLength !== undefined && keys.length < minLength)
|
|
180
|
-
return false;
|
|
181
|
-
if (maxLength !== undefined && keys.length > maxLength)
|
|
182
|
-
return false;
|
|
183
|
-
return true;
|
|
184
|
-
}
|
|
185
|
-
export function isValidArray(value, minLength, maxLength) {
|
|
186
|
-
if (value === undefined || value === null || !Array.isArray(value))
|
|
187
|
-
return false;
|
|
188
|
-
if (minLength !== undefined && value.length < minLength)
|
|
189
|
-
return false;
|
|
190
|
-
if (maxLength !== undefined && value.length > maxLength)
|
|
191
|
-
return false;
|
|
192
|
-
return true;
|
|
193
|
-
}
|
|
194
|
-
export function isValidNull(value) {
|
|
195
|
-
return value === null;
|
|
196
|
-
}
|
|
197
|
-
export function isValidUndefined(value) {
|
|
198
|
-
return value === undefined;
|
|
199
|
-
}
|
|
200
150
|
export function logInterfaces(debug = true) {
|
|
201
151
|
log.logLevel = "info";
|
|
202
152
|
log.logName = 'LogInterfaces';
|
|
@@ -260,7 +210,7 @@ export async function wait(timeout = 1000, name, debug = false) {
|
|
|
260
210
|
export async function createZip(outputPath, ...sourcePaths) {
|
|
261
211
|
const { default: archiver } = await import('archiver');
|
|
262
212
|
const { glob } = await import('glob');
|
|
263
|
-
const { createWriteStream, statSync } = await import('fs');
|
|
213
|
+
const { createWriteStream, statSync } = await import('node:fs');
|
|
264
214
|
log.logLevel = "info";
|
|
265
215
|
log.logName = 'Archive';
|
|
266
216
|
log.debug(`creating archive ${outputPath} from ${sourcePaths.join(', ')} ...`);
|
|
@@ -326,7 +276,7 @@ export async function createZip(outputPath, ...sourcePaths) {
|
|
|
326
276
|
});
|
|
327
277
|
}
|
|
328
278
|
export async function copyDirectory(srcDir, destDir) {
|
|
329
|
-
const fs = await import('fs').then((mod) => mod.promises);
|
|
279
|
+
const fs = await import('node:fs').then((mod) => mod.promises);
|
|
330
280
|
log.debug(`copyDirectory: copying directory from ${srcDir} to ${destDir}`);
|
|
331
281
|
try {
|
|
332
282
|
await fs.mkdir(destDir, { recursive: true });
|
|
@@ -349,7 +299,7 @@ export async function copyDirectory(srcDir, destDir) {
|
|
|
349
299
|
}
|
|
350
300
|
}
|
|
351
301
|
export async function resolveHostname(hostname, family = 4) {
|
|
352
|
-
const dns = await import('dns');
|
|
302
|
+
const dns = await import('node:dns');
|
|
353
303
|
try {
|
|
354
304
|
const addresses = await dns.promises.lookup(hostname.toLowerCase(), { family });
|
|
355
305
|
return addresses.address;
|
|
@@ -358,31 +308,6 @@ export async function resolveHostname(hostname, family = 4) {
|
|
|
358
308
|
return null;
|
|
359
309
|
}
|
|
360
310
|
}
|
|
361
|
-
export function getParameter(name) {
|
|
362
|
-
const commandArguments = process.argv.slice(2);
|
|
363
|
-
let markerIndex = commandArguments.indexOf(`-${name}`);
|
|
364
|
-
if (markerIndex === -1)
|
|
365
|
-
markerIndex = commandArguments.indexOf(`--${name}`);
|
|
366
|
-
if (markerIndex === -1 || markerIndex + 1 === commandArguments.length)
|
|
367
|
-
return undefined;
|
|
368
|
-
return commandArguments[markerIndex + 1];
|
|
369
|
-
}
|
|
370
|
-
export function hasParameter(name) {
|
|
371
|
-
const commandArguments = process.argv.slice(2);
|
|
372
|
-
let markerIncluded = commandArguments.includes(`-${name}`);
|
|
373
|
-
if (!markerIncluded)
|
|
374
|
-
markerIncluded = commandArguments.includes(`--${name}`);
|
|
375
|
-
return markerIncluded;
|
|
376
|
-
}
|
|
377
|
-
export function getIntParameter(name) {
|
|
378
|
-
const value = getParameter(name);
|
|
379
|
-
if (value === undefined)
|
|
380
|
-
return undefined;
|
|
381
|
-
const intValue = parseInt(value, 10);
|
|
382
|
-
if (!isValidNumber(intValue))
|
|
383
|
-
return undefined;
|
|
384
|
-
return intValue;
|
|
385
|
-
}
|
|
386
311
|
export async function getNpmPackageVersion(packageName, tag = 'latest', timeout = 5000) {
|
|
387
312
|
const https = await import('https');
|
|
388
313
|
return new Promise((resolve, reject) => {
|
|
@@ -427,3 +352,16 @@ export async function getNpmPackageVersion(packageName, tag = 'latest', timeout
|
|
|
427
352
|
});
|
|
428
353
|
});
|
|
429
354
|
}
|
|
355
|
+
export async function getGlobalNodeModules() {
|
|
356
|
+
const { exec } = await import('node:child_process');
|
|
357
|
+
return new Promise((resolve, reject) => {
|
|
358
|
+
exec('npm root -g', (error, stdout) => {
|
|
359
|
+
if (error) {
|
|
360
|
+
reject(error);
|
|
361
|
+
}
|
|
362
|
+
else {
|
|
363
|
+
resolve(stdout.trim());
|
|
364
|
+
}
|
|
365
|
+
});
|
|
366
|
+
});
|
|
367
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"files": {
|
|
3
3
|
"main.css": "./static/css/main.cf25d33e.css",
|
|
4
|
-
"main.js": "./static/js/main.
|
|
4
|
+
"main.js": "./static/js/main.438c6c47.js",
|
|
5
5
|
"static/js/453.abd36b29.chunk.js": "./static/js/453.abd36b29.chunk.js",
|
|
6
6
|
"static/media/roboto-latin-700-normal.woff2": "./static/media/roboto-latin-700-normal.4535474e1cf8598695ad.woff2",
|
|
7
7
|
"static/media/roboto-latin-500-normal.woff2": "./static/media/roboto-latin-500-normal.7077203b1982951ecf76.woff2",
|
|
@@ -61,11 +61,11 @@
|
|
|
61
61
|
"static/media/roboto-greek-ext-400-normal.woff": "./static/media/roboto-greek-ext-400-normal.16eb83b4a3b1ea994243.woff",
|
|
62
62
|
"index.html": "./index.html",
|
|
63
63
|
"main.cf25d33e.css.map": "./static/css/main.cf25d33e.css.map",
|
|
64
|
-
"main.
|
|
64
|
+
"main.438c6c47.js.map": "./static/js/main.438c6c47.js.map",
|
|
65
65
|
"453.abd36b29.chunk.js.map": "./static/js/453.abd36b29.chunk.js.map"
|
|
66
66
|
},
|
|
67
67
|
"entrypoints": [
|
|
68
68
|
"static/css/main.cf25d33e.css",
|
|
69
|
-
"static/js/main.
|
|
69
|
+
"static/js/main.438c6c47.js"
|
|
70
70
|
]
|
|
71
71
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
<!doctype html><html lang="en"><head><meta charset="utf-8"/><base href="./"><link rel="icon" href="./matterbridge 32x32.png"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><title>Matterbridge</title><link rel="manifest" href="./manifest.json"/><script defer="defer" src="./static/js/main.
|
|
1
|
+
<!doctype html><html lang="en"><head><meta charset="utf-8"/><base href="./"><link rel="icon" href="./matterbridge 32x32.png"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><title>Matterbridge</title><link rel="manifest" href="./manifest.json"/><script defer="defer" src="./static/js/main.438c6c47.js"></script><link href="./static/css/main.cf25d33e.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
|