matterbridge 1.2.12 → 1.2.14
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 +30 -0
- package/README.md +9 -4
- package/dist/BridgedDeviceBasicInformationCluster.d.ts +223 -0
- package/dist/BridgedDeviceBasicInformationCluster.d.ts.map +1 -0
- package/dist/BridgedDeviceBasicInformationCluster.js +176 -0
- package/dist/BridgedDeviceBasicInformationCluster.js.map +1 -0
- package/dist/defaultConfigSchema.d.ts +28 -0
- package/dist/defaultConfigSchema.d.ts.map +1 -0
- package/dist/defaultConfigSchema.js +217 -0
- package/dist/defaultConfigSchema.js.map +1 -0
- package/dist/matterbridge.d.ts +22 -0
- package/dist/matterbridge.d.ts.map +1 -1
- package/dist/matterbridge.js +284 -70
- package/dist/matterbridge.js.map +1 -1
- package/dist/matterbridgeAccessoryPlatform.d.ts.map +1 -1
- package/dist/matterbridgeAccessoryPlatform.js.map +1 -1
- package/dist/matterbridgeDevice.d.ts +60 -15
- package/dist/matterbridgeDevice.d.ts.map +1 -1
- package/dist/matterbridgeDevice.js +7 -3
- package/dist/matterbridgeDevice.js.map +1 -1
- package/dist/matterbridgePlatform.d.ts +1 -0
- package/dist/matterbridgePlatform.d.ts.map +1 -1
- package/dist/matterbridgePlatform.js +1 -0
- package/dist/matterbridgePlatform.js.map +1 -1
- package/frontend/build/asset-manifest.json +6 -6
- package/frontend/build/index.html +1 -1
- package/frontend/build/static/css/main.979e07d2.css +2 -0
- package/frontend/build/static/css/main.979e07d2.css.map +1 -0
- package/frontend/build/static/js/main.ed3f81ca.js +3 -0
- package/frontend/build/static/js/main.ed3f81ca.js.map +1 -0
- package/package.json +14 -8
- package/frontend/build/static/css/main.1880392b.css +0 -2
- package/frontend/build/static/css/main.1880392b.css.map +0 -1
- package/frontend/build/static/js/main.0c70c26b.js +0 -3
- package/frontend/build/static/js/main.0c70c26b.js.map +0 -1
- /package/frontend/build/static/js/{main.0c70c26b.js.LICENSE.txt → main.ed3f81ca.js.LICENSE.txt} +0 -0
package/dist/matterbridge.js
CHANGED
|
@@ -32,8 +32,9 @@ import express from 'express';
|
|
|
32
32
|
import os from 'os';
|
|
33
33
|
import path from 'path';
|
|
34
34
|
import WebSocket, { WebSocketServer } from 'ws';
|
|
35
|
+
import { BridgedDeviceBasicInformation, BridgedDeviceBasicInformationCluster } from './BridgedDeviceBasicInformationCluster.js';
|
|
35
36
|
import { CommissioningController, CommissioningServer, MatterServer } from '@project-chip/matter-node.js';
|
|
36
|
-
import { BasicInformationCluster, BooleanStateCluster,
|
|
37
|
+
import { BasicInformationCluster, BooleanStateCluster, ClusterServer, FixedLabelCluster, GeneralCommissioning, GeneralDiagnostics, GeneralDiagnosticsCluster, PowerSourceCluster, ThreadNetworkDiagnosticsCluster, getClusterNameById, } from '@project-chip/matter-node.js/cluster';
|
|
37
38
|
import { DeviceTypeId, VendorId } from '@project-chip/matter-node.js/datatype';
|
|
38
39
|
import { Aggregator, DeviceTypes, NodeStateInformation } from '@project-chip/matter-node.js/device';
|
|
39
40
|
import { Format, Level, Logger } from '@project-chip/matter-node.js/log';
|
|
@@ -41,6 +42,7 @@ import { ManualPairingCodeCodec, QrCodeSchema } from '@project-chip/matter-node.
|
|
|
41
42
|
import { StorageBackendDisk, StorageBackendJsonFile, StorageManager } from '@project-chip/matter-node.js/storage';
|
|
42
43
|
import { requireMinNodeVersion, getParameter, getIntParameter, hasParameter } from '@project-chip/matter-node.js/util';
|
|
43
44
|
import { CryptoNode } from '@project-chip/matter-node.js/crypto';
|
|
45
|
+
import { somfytahoma_config, somfytahoma_schema, zigbee2mqtt_config, zigbee2mqtt_schema } from './defaultConfigSchema.js';
|
|
44
46
|
const plg = '\u001B[38;5;33m';
|
|
45
47
|
const dev = '\u001B[38;5;79m';
|
|
46
48
|
const typ = '\u001B[38;5;207m';
|
|
@@ -49,6 +51,7 @@ const typ = '\u001B[38;5;207m';
|
|
|
49
51
|
*/
|
|
50
52
|
export class Matterbridge extends EventEmitter {
|
|
51
53
|
systemInformation = {
|
|
54
|
+
macAddress: '',
|
|
52
55
|
ipv4Address: '',
|
|
53
56
|
ipv6Address: '',
|
|
54
57
|
nodeVersion: '',
|
|
@@ -156,7 +159,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
156
159
|
addedDevices: 0,
|
|
157
160
|
};
|
|
158
161
|
this.registeredPlugins.push(plugin);
|
|
159
|
-
await this.nodeContext?.set('plugins', this.getBaseRegisteredPlugins());
|
|
162
|
+
await this.nodeContext?.set('plugins', await this.getBaseRegisteredPlugins());
|
|
160
163
|
// Log system info and create .matterbridge directory
|
|
161
164
|
await this.logNodeAndSystemInfo();
|
|
162
165
|
this.matterbridgeDirectory = dataPath;
|
|
@@ -498,7 +501,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
498
501
|
const plugin = { path: packageJsonPath, type: '', name: packageJson.name, version: packageJson.version, description: packageJson.description, author: packageJson.author, enabled: true };
|
|
499
502
|
if (await this.loadPlugin(plugin)) {
|
|
500
503
|
this.registeredPlugins.push(plugin);
|
|
501
|
-
await this.nodeContext?.set('plugins', this.getBaseRegisteredPlugins());
|
|
504
|
+
await this.nodeContext?.set('plugins', await this.getBaseRegisteredPlugins());
|
|
502
505
|
this.log.info(`Plugin ${plg}${packageJsonPath}${nf} type ${plugin.type} added to matterbridge`);
|
|
503
506
|
}
|
|
504
507
|
else {
|
|
@@ -512,7 +515,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
512
515
|
else if (mode === 'remove') {
|
|
513
516
|
if (this.registeredPlugins.find((registeredPlugin) => registeredPlugin.name === packageJson.name)) {
|
|
514
517
|
this.registeredPlugins.splice(this.registeredPlugins.findIndex((registeredPlugin) => registeredPlugin.name === packageJson.name), 1);
|
|
515
|
-
await this.nodeContext?.set('plugins', this.getBaseRegisteredPlugins());
|
|
518
|
+
await this.nodeContext?.set('plugins', await this.getBaseRegisteredPlugins());
|
|
516
519
|
this.log.info(`Plugin ${plg}${packageJsonPath}${nf} removed from matterbridge`);
|
|
517
520
|
}
|
|
518
521
|
else {
|
|
@@ -527,7 +530,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
527
530
|
plugin.started = undefined;
|
|
528
531
|
plugin.configured = undefined;
|
|
529
532
|
plugin.connected = undefined;
|
|
530
|
-
await this.nodeContext?.set('plugins', this.getBaseRegisteredPlugins());
|
|
533
|
+
await this.nodeContext?.set('plugins', await this.getBaseRegisteredPlugins());
|
|
531
534
|
this.log.info(`Plugin ${plg}${packageJsonPath}${nf} enabled`);
|
|
532
535
|
}
|
|
533
536
|
else {
|
|
@@ -542,7 +545,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
542
545
|
plugin.started = undefined;
|
|
543
546
|
plugin.configured = undefined;
|
|
544
547
|
plugin.connected = undefined;
|
|
545
|
-
await this.nodeContext?.set('plugins', this.getBaseRegisteredPlugins());
|
|
548
|
+
await this.nodeContext?.set('plugins', await this.getBaseRegisteredPlugins());
|
|
546
549
|
this.log.info(`Plugin ${plg}${packageJsonPath}${nf} disabled`);
|
|
547
550
|
}
|
|
548
551
|
else {
|
|
@@ -564,7 +567,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
564
567
|
if (!context)
|
|
565
568
|
this.log.error(`Plugin ${plg}${plugin.name}${er} context not found`);
|
|
566
569
|
await context?.clearAll();
|
|
567
|
-
await this.nodeContext?.set('plugins', this.getBaseRegisteredPlugins());
|
|
570
|
+
await this.nodeContext?.set('plugins', await this.getBaseRegisteredPlugins());
|
|
568
571
|
this.log.info(`Reset commissionig for plugin ${plg}${plugin.name}${nf} done! Remove the device from the controller.`);
|
|
569
572
|
}
|
|
570
573
|
else {
|
|
@@ -655,7 +658,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
655
658
|
if (plugin.platform) {
|
|
656
659
|
try {
|
|
657
660
|
await plugin.platform.onShutdown('Matterbridge is closing: ' + message);
|
|
658
|
-
await this.savePluginConfig(plugin);
|
|
661
|
+
// await this.savePluginConfig(plugin);
|
|
659
662
|
}
|
|
660
663
|
catch (error) {
|
|
661
664
|
this.log.error(`Plugin ${plg}${plugin.name}${er} shutting down error: ${error}`);
|
|
@@ -991,7 +994,8 @@ export class Matterbridge extends EventEmitter {
|
|
|
991
994
|
}
|
|
992
995
|
}
|
|
993
996
|
catch (error) {
|
|
994
|
-
this.log.error('Storage initialize() error!');
|
|
997
|
+
this.log.error('Storage initialize() error! The file .matterbridge/matterbridge.json may be corrupted.');
|
|
998
|
+
this.log.error('Please delete it and rename matterbridge.backup.json to matterbridge.json and try to restart Matterbridge.');
|
|
995
999
|
await this.cleanup('Storage initialize() error!');
|
|
996
1000
|
}
|
|
997
1001
|
}
|
|
@@ -1122,6 +1126,97 @@ export class Matterbridge extends EventEmitter {
|
|
|
1122
1126
|
}, 60 * 1000);
|
|
1123
1127
|
}, 1000);
|
|
1124
1128
|
}
|
|
1129
|
+
/**
|
|
1130
|
+
* Loads the schema for a plugin.
|
|
1131
|
+
* If the schema file exists, it reads the file and returns the parsed JSON data.
|
|
1132
|
+
* If the schema file does not exist, it creates a new file with default configuration and returns it.
|
|
1133
|
+
* If any error occurs during file access or creation, it logs an error and return an empty schema.
|
|
1134
|
+
*
|
|
1135
|
+
* @param plugin - The plugin for which to load the schema.
|
|
1136
|
+
* @returns A promise that resolves to the loaded or created schema.
|
|
1137
|
+
*/
|
|
1138
|
+
async loadPluginSchema(plugin) {
|
|
1139
|
+
const schemaFile = path.join(this.matterbridgeDirectory, `${plugin.name}.schema.json`);
|
|
1140
|
+
try {
|
|
1141
|
+
await fs.access(schemaFile);
|
|
1142
|
+
const data = await fs.readFile(schemaFile, 'utf8');
|
|
1143
|
+
const schema = JSON.parse(data);
|
|
1144
|
+
schema.title = plugin.description;
|
|
1145
|
+
schema.description = plugin.name + ' v. ' + plugin.version + ' by ' + plugin.author;
|
|
1146
|
+
this.log.debug(`Schema file found: ${schemaFile}.\nSchema:${rs}\n`, schema);
|
|
1147
|
+
return schema;
|
|
1148
|
+
}
|
|
1149
|
+
catch (err) {
|
|
1150
|
+
if (err instanceof Error) {
|
|
1151
|
+
const nodeErr = err;
|
|
1152
|
+
if (nodeErr.code === 'ENOENT') {
|
|
1153
|
+
let schema;
|
|
1154
|
+
if (plugin.name === 'matterbridge-zigbee2mqtt')
|
|
1155
|
+
schema = zigbee2mqtt_schema;
|
|
1156
|
+
else if (plugin.name === 'matterbridge-somfy-tahoma')
|
|
1157
|
+
schema = somfytahoma_schema;
|
|
1158
|
+
else
|
|
1159
|
+
schema = {
|
|
1160
|
+
title: plugin.description,
|
|
1161
|
+
description: plugin.name + ' v. ' + plugin.version + ' by ' + plugin.author,
|
|
1162
|
+
type: 'object',
|
|
1163
|
+
properties: {
|
|
1164
|
+
name: {
|
|
1165
|
+
description: 'Plugin name',
|
|
1166
|
+
type: 'string',
|
|
1167
|
+
readOnly: true,
|
|
1168
|
+
},
|
|
1169
|
+
type: {
|
|
1170
|
+
description: 'Plugin type',
|
|
1171
|
+
type: 'string',
|
|
1172
|
+
readOnly: true,
|
|
1173
|
+
},
|
|
1174
|
+
unregisterOnShutdown: {
|
|
1175
|
+
description: 'Unregister all devices on shutdown (development only)',
|
|
1176
|
+
type: 'boolean',
|
|
1177
|
+
},
|
|
1178
|
+
},
|
|
1179
|
+
};
|
|
1180
|
+
try {
|
|
1181
|
+
await this.writeFile(schemaFile, JSON.stringify(schema, null, 2));
|
|
1182
|
+
this.log.debug(`Created schema file: ${schemaFile}.\nSchema:${rs}\n`, schema);
|
|
1183
|
+
return schema;
|
|
1184
|
+
}
|
|
1185
|
+
catch (err) {
|
|
1186
|
+
this.log.error(`Error creating schema file ${schemaFile}: ${err}`);
|
|
1187
|
+
return schema;
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1190
|
+
else {
|
|
1191
|
+
this.log.error(`Error accessing schema file ${schemaFile}: ${err}`);
|
|
1192
|
+
return {};
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
this.log.error(`Error loading schema file ${schemaFile}: ${err}`);
|
|
1196
|
+
return {};
|
|
1197
|
+
}
|
|
1198
|
+
}
|
|
1199
|
+
/**
|
|
1200
|
+
* Saves the plugin configuration to a JSON file.
|
|
1201
|
+
* @param plugin - The registered plugin.
|
|
1202
|
+
* @param config - The platform configuration.
|
|
1203
|
+
* @returns A promise that resolves when the configuration is saved successfully, or rejects with an error.
|
|
1204
|
+
*/
|
|
1205
|
+
async savePluginConfigFromJson(plugin, config) {
|
|
1206
|
+
if (!config.name || !config.type || config.name !== plugin.name) {
|
|
1207
|
+
this.log.error(`Error saving plugin ${plg}${plugin.name}${er} config`);
|
|
1208
|
+
return;
|
|
1209
|
+
}
|
|
1210
|
+
const configFile = path.join(this.matterbridgeDirectory, `${plugin.name}.config.json`);
|
|
1211
|
+
try {
|
|
1212
|
+
await this.writeFile(configFile, JSON.stringify(config, null, 2));
|
|
1213
|
+
this.log.debug(`Saved config file: ${configFile}.\nConfig:${rs}\n`, config);
|
|
1214
|
+
}
|
|
1215
|
+
catch (err) {
|
|
1216
|
+
this.log.error(`Error saving plugin ${plg}${plugin.name}${er} config: ${err}`);
|
|
1217
|
+
return;
|
|
1218
|
+
}
|
|
1219
|
+
}
|
|
1125
1220
|
/**
|
|
1126
1221
|
* Loads the configuration for a plugin.
|
|
1127
1222
|
* If the configuration file exists, it reads the file and returns the parsed JSON data.
|
|
@@ -1147,22 +1242,30 @@ export class Matterbridge extends EventEmitter {
|
|
|
1147
1242
|
if (err instanceof Error) {
|
|
1148
1243
|
const nodeErr = err;
|
|
1149
1244
|
if (nodeErr.code === 'ENOENT') {
|
|
1245
|
+
let config;
|
|
1246
|
+
if (plugin.name === 'matterbridge-zigbee2mqtt')
|
|
1247
|
+
config = zigbee2mqtt_config;
|
|
1248
|
+
else if (plugin.name === 'matterbridge-somfy-tahoma')
|
|
1249
|
+
config = somfytahoma_config;
|
|
1250
|
+
else
|
|
1251
|
+
config = { name: plugin.name, type: plugin.type, unregisterOnShutdown: false };
|
|
1150
1252
|
try {
|
|
1151
|
-
await this.writeFile(configFile, JSON.stringify(
|
|
1152
|
-
this.log.debug(`Created config file: ${configFile}.\nConfig:${rs}\n`,
|
|
1153
|
-
return
|
|
1253
|
+
await this.writeFile(configFile, JSON.stringify(config, null, 2));
|
|
1254
|
+
this.log.debug(`Created config file: ${configFile}.\nConfig:${rs}\n`, config);
|
|
1255
|
+
return config;
|
|
1154
1256
|
}
|
|
1155
1257
|
catch (err) {
|
|
1156
1258
|
this.log.error(`Error creating config file ${configFile}: ${err}`);
|
|
1157
|
-
return
|
|
1259
|
+
return config;
|
|
1158
1260
|
}
|
|
1159
1261
|
}
|
|
1160
1262
|
else {
|
|
1161
1263
|
this.log.error(`Error accessing config file ${configFile}: ${err}`);
|
|
1162
|
-
return
|
|
1264
|
+
return {};
|
|
1163
1265
|
}
|
|
1164
1266
|
}
|
|
1165
|
-
|
|
1267
|
+
this.log.error(`Error loading config file ${configFile}: ${err}`);
|
|
1268
|
+
return {};
|
|
1166
1269
|
}
|
|
1167
1270
|
}
|
|
1168
1271
|
/**
|
|
@@ -1266,6 +1369,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
1266
1369
|
.then(() => {
|
|
1267
1370
|
plugin.configured = true;
|
|
1268
1371
|
this.log.info(`Configured plugin ${plg}${plugin.name}${db} type ${typ}${plugin.type}${db}`);
|
|
1372
|
+
this.savePluginConfig(plugin);
|
|
1269
1373
|
return Promise.resolve();
|
|
1270
1374
|
})
|
|
1271
1375
|
.catch((err) => {
|
|
@@ -1297,7 +1401,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
1297
1401
|
this.log.error(`Plugin ${plg}${plugin.name}${er} already loaded`);
|
|
1298
1402
|
return Promise.resolve(plugin.platform);
|
|
1299
1403
|
}
|
|
1300
|
-
this.log.info(`Loading plugin ${plg}${plugin.name}${
|
|
1404
|
+
this.log.info(`Loading plugin ${plg}${plugin.name}${nf} type ${typ}${plugin.type}${nf}`);
|
|
1301
1405
|
try {
|
|
1302
1406
|
// Load the package.json of the plugin
|
|
1303
1407
|
const packageJson = JSON.parse(await fs.readFile(plugin.path, 'utf8'));
|
|
@@ -1316,6 +1420,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
1316
1420
|
const platform = pluginInstance.default(this, log, config);
|
|
1317
1421
|
platform.name = packageJson.name;
|
|
1318
1422
|
platform.config = config;
|
|
1423
|
+
platform.version = packageJson.version;
|
|
1319
1424
|
plugin.name = packageJson.name;
|
|
1320
1425
|
plugin.description = packageJson.description;
|
|
1321
1426
|
plugin.version = packageJson.version;
|
|
@@ -1325,8 +1430,20 @@ export class Matterbridge extends EventEmitter {
|
|
|
1325
1430
|
plugin.loaded = true;
|
|
1326
1431
|
plugin.registeredDevices = 0;
|
|
1327
1432
|
plugin.addedDevices = 0;
|
|
1328
|
-
await this.nodeContext?.set('plugins', this.getBaseRegisteredPlugins());
|
|
1329
|
-
this.
|
|
1433
|
+
await this.nodeContext?.set('plugins', await this.getBaseRegisteredPlugins());
|
|
1434
|
+
this.getLatestVersion(plugin.name)
|
|
1435
|
+
.then(async (latestVersion) => {
|
|
1436
|
+
plugin.latestVersion = latestVersion;
|
|
1437
|
+
await this.nodeContext?.set('plugins', await this.getBaseRegisteredPlugins());
|
|
1438
|
+
if (plugin.version !== latestVersion)
|
|
1439
|
+
this.log.warn(`The plugin ${plg}${plugin.name}${wr} is out of date. Current version: ${plugin.version}, Latest version: ${latestVersion}`);
|
|
1440
|
+
else
|
|
1441
|
+
this.log.info(`The plugin ${plg}${plugin.name}${nf} is up to date. Current version: ${plugin.version}, Latest version: ${latestVersion}`);
|
|
1442
|
+
})
|
|
1443
|
+
.catch((error) => {
|
|
1444
|
+
this.log.error(`Error getting ${plugin.name} latest version: ${error}`);
|
|
1445
|
+
});
|
|
1446
|
+
this.log.info(`Loaded plugin ${plg}${plugin.name}${nf} type ${typ}${platform.type} ${db}(entrypoint ${UNDERLINE}${pluginEntry}${UNDERLINEOFF})`);
|
|
1330
1447
|
if (start)
|
|
1331
1448
|
this.startPlugin(plugin, message); // No await do it asyncronously
|
|
1332
1449
|
return Promise.resolve(platform);
|
|
@@ -1555,8 +1672,6 @@ export class Matterbridge extends EventEmitter {
|
|
|
1555
1672
|
this.log.error(`Node storage context undefined for ${plg}Matterbridge${er}`);
|
|
1556
1673
|
return;
|
|
1557
1674
|
}
|
|
1558
|
-
await this.matterbridgeContext.set('softwareVersion', 1);
|
|
1559
|
-
await this.matterbridgeContext.set('softwareVersionString', this.matterbridgeVersion);
|
|
1560
1675
|
this.log.debug(`Creating commissioning server for ${plg}Matterbridge${db}`);
|
|
1561
1676
|
this.commissioningServer = await this.createCommisioningServer(this.matterbridgeContext, 'Matterbridge');
|
|
1562
1677
|
this.log.debug(`Creating matter aggregator for ${plg}Matterbridge${db}`);
|
|
@@ -1568,6 +1683,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
1568
1683
|
await this.startMatterServer();
|
|
1569
1684
|
this.log.info('Matter server started');
|
|
1570
1685
|
await this.showCommissioningQRCode(this.commissioningServer, this.matterbridgeContext, this.nodeContext, 'Matterbridge');
|
|
1686
|
+
// logEndpoint(this.commissioningServer.getRootEndpoint());
|
|
1571
1687
|
//if (hasParameter('advertise')) await this.commissioningServer.advertise();
|
|
1572
1688
|
setTimeout(() => {
|
|
1573
1689
|
this.log.info(`Setting reachability to true for ${plg}Matterbridge${db}`);
|
|
@@ -1606,8 +1722,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
1606
1722
|
continue;
|
|
1607
1723
|
if (!plugin.storageContext)
|
|
1608
1724
|
plugin.storageContext = await this.importCommissioningServerContext(plugin.name, registeredDevice.device);
|
|
1609
|
-
|
|
1610
|
-
await plugin.storageContext.set('softwareVersionString', this.matterbridgeVersion);
|
|
1725
|
+
this.log.debug(`Creating commissioning server for ${plg}${plugin.name}${db}`);
|
|
1611
1726
|
if (!plugin.commissioningServer)
|
|
1612
1727
|
plugin.commissioningServer = await this.createCommisioningServer(plugin.storageContext, plugin.name);
|
|
1613
1728
|
this.log.debug(`Adding device ${dev}${registeredDevice.device.name}${db} to commissioning server for plugin ${plg}${plugin.name}${db}`);
|
|
@@ -1619,10 +1734,9 @@ export class Matterbridge extends EventEmitter {
|
|
|
1619
1734
|
await this.matterServer?.addCommissioningServer(plugin.commissioningServer, { uniqueStorageKey: plugin.name });
|
|
1620
1735
|
}
|
|
1621
1736
|
if (plugin.type === 'DynamicPlatform') {
|
|
1622
|
-
|
|
1737
|
+
this.log.debug(`Creating commissioning server context for ${plg}${plugin.name}${db}`);
|
|
1623
1738
|
plugin.storageContext = await this.createCommissioningServerContext(plugin.name, 'Matterbridge', DeviceTypes.AGGREGATOR.code, 0xfff1, 'Matterbridge', 0x8000, 'Matterbridge Dynamic Platform');
|
|
1624
|
-
|
|
1625
|
-
await plugin.storageContext.set('softwareVersionString', this.matterbridgeVersion);
|
|
1739
|
+
this.log.debug(`Creating commissioning server for ${plg}${plugin.name}${db}`);
|
|
1626
1740
|
plugin.commissioningServer = await this.createCommisioningServer(plugin.storageContext, plugin.name);
|
|
1627
1741
|
this.log.debug(`Creating aggregator for plugin ${plg}${plugin.name}${db}`);
|
|
1628
1742
|
plugin.aggregator = await this.createMatterAggregator(plugin.storageContext); // Generate serialNumber and uniqueId
|
|
@@ -1711,10 +1825,35 @@ export class Matterbridge extends EventEmitter {
|
|
|
1711
1825
|
this.log.debug(`Importing matter commissioning server storage context from device for ${plg}${pluginName}${db}`);
|
|
1712
1826
|
const basic = device.getClusterServer(BasicInformationCluster);
|
|
1713
1827
|
if (!basic) {
|
|
1714
|
-
|
|
1828
|
+
this.log.error('importCommissioningServerContext error: cannot find the BasicInformationCluster');
|
|
1829
|
+
process.exit(1);
|
|
1830
|
+
}
|
|
1831
|
+
if (!this.storageManager) {
|
|
1832
|
+
this.log.error('importCommissioningServerContext error: no storage manager initialized');
|
|
1833
|
+
process.exit(1);
|
|
1715
1834
|
}
|
|
1716
|
-
|
|
1717
|
-
|
|
1835
|
+
this.log.debug(`Importing commissioning server storage context for ${plg}${pluginName}${db}`);
|
|
1836
|
+
const storageContext = this.storageManager.createContext(pluginName);
|
|
1837
|
+
await storageContext.set('deviceName', basic.getNodeLabelAttribute());
|
|
1838
|
+
await storageContext.set('deviceType', DeviceTypeId(device.deviceType));
|
|
1839
|
+
await storageContext.set('vendorId', basic.getVendorIdAttribute());
|
|
1840
|
+
await storageContext.set('vendorName', basic.getVendorNameAttribute());
|
|
1841
|
+
await storageContext.set('productId', basic.getProductIdAttribute());
|
|
1842
|
+
await storageContext.set('productName', basic.getProductNameAttribute());
|
|
1843
|
+
await storageContext.set('nodeLabel', basic.getNodeLabelAttribute());
|
|
1844
|
+
await storageContext.set('productLabel', basic.getNodeLabelAttribute());
|
|
1845
|
+
await storageContext.set('serialNumber', basic.attributes.serialNumber?.getLocal());
|
|
1846
|
+
await storageContext.set('uniqueId', basic.attributes.uniqueId?.getLocal());
|
|
1847
|
+
await storageContext.set('softwareVersion', basic.getSoftwareVersionAttribute());
|
|
1848
|
+
await storageContext.set('softwareVersionString', basic.getSoftwareVersionStringAttribute());
|
|
1849
|
+
await storageContext.set('hardwareVersion', basic.getHardwareVersionAttribute());
|
|
1850
|
+
await storageContext.set('hardwareVersionString', basic.getHardwareVersionStringAttribute());
|
|
1851
|
+
this.log.debug(`Imported commissioning server storage context for ${plg}${pluginName}${db}`);
|
|
1852
|
+
this.log.debug(`- deviceName: ${await storageContext.get('deviceName')} deviceType: ${await storageContext.get('deviceType')}(0x${(await storageContext.get('deviceType'))?.toString(16).padStart(4, '0')})`);
|
|
1853
|
+
this.log.debug(`- serialNumber: ${await storageContext.get('serialNumber')} uniqueId: ${await storageContext.get('uniqueId')}`);
|
|
1854
|
+
this.log.debug(`- softwareVersion: ${await storageContext.get('softwareVersion')} softwareVersionString: ${await storageContext.get('softwareVersionString')}`);
|
|
1855
|
+
this.log.debug(`- hardwareVersion: ${await storageContext.get('hardwareVersion')} hardwareVersionString: ${await storageContext.get('hardwareVersionString')}`);
|
|
1856
|
+
return storageContext;
|
|
1718
1857
|
}
|
|
1719
1858
|
/**
|
|
1720
1859
|
* Creates a commissioning server storage context.
|
|
@@ -1734,7 +1873,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
1734
1873
|
* @param hardwareVersionString - The hardware version string of the device (optional).
|
|
1735
1874
|
* @returns The storage context for the commissioning server.
|
|
1736
1875
|
*/
|
|
1737
|
-
async createCommissioningServerContext(pluginName, deviceName, deviceType, vendorId, vendorName, productId, productName
|
|
1876
|
+
async createCommissioningServerContext(pluginName, deviceName, deviceType, vendorId, vendorName, productId, productName) {
|
|
1738
1877
|
if (!this.storageManager) {
|
|
1739
1878
|
this.log.error('No storage manager initialized');
|
|
1740
1879
|
process.exit(1);
|
|
@@ -1752,11 +1891,13 @@ export class Matterbridge extends EventEmitter {
|
|
|
1752
1891
|
await storageContext.set('productLabel', productName.slice(0, 32));
|
|
1753
1892
|
await storageContext.set('serialNumber', await storageContext.get('serialNumber', random));
|
|
1754
1893
|
await storageContext.set('uniqueId', await storageContext.get('uniqueId', random));
|
|
1755
|
-
await storageContext.set('softwareVersion',
|
|
1756
|
-
await storageContext.set('softwareVersionString',
|
|
1757
|
-
await storageContext.set('hardwareVersion',
|
|
1758
|
-
await storageContext.set('hardwareVersionString',
|
|
1894
|
+
await storageContext.set('softwareVersion', this.matterbridgeVersion && this.matterbridgeVersion.includes('.') ? parseInt(this.matterbridgeVersion.split('.')[0], 10) : 1);
|
|
1895
|
+
await storageContext.set('softwareVersionString', this.matterbridgeVersion ?? '1.0.0');
|
|
1896
|
+
await storageContext.set('hardwareVersion', this.systemInformation.osRelease && this.systemInformation.osRelease.includes('.') ? parseInt(this.systemInformation.osRelease.split('.')[0], 10) : 1);
|
|
1897
|
+
await storageContext.set('hardwareVersionString', this.systemInformation.osRelease ?? '1.0.0');
|
|
1759
1898
|
this.log.debug(`Created commissioning server storage context for ${plg}${pluginName}${db}`);
|
|
1899
|
+
this.log.debug(`- deviceName: ${await storageContext.get('deviceName')} deviceType: ${await storageContext.get('deviceType')}(0x${(await storageContext.get('deviceType'))?.toString(16).padStart(4, '0')})`);
|
|
1900
|
+
this.log.debug(`- serialNumber: ${await storageContext.get('serialNumber')} uniqueId: ${await storageContext.get('uniqueId')}`);
|
|
1760
1901
|
this.log.debug(`- softwareVersion: ${await storageContext.get('softwareVersion')} softwareVersionString: ${await storageContext.get('softwareVersionString')}`);
|
|
1761
1902
|
this.log.debug(`- hardwareVersion: ${await storageContext.get('hardwareVersion')} hardwareVersionString: ${await storageContext.get('hardwareVersionString')}`);
|
|
1762
1903
|
return storageContext;
|
|
@@ -1773,14 +1914,14 @@ export class Matterbridge extends EventEmitter {
|
|
|
1773
1914
|
if (!commissioningServer || !storageContext || !pluginName)
|
|
1774
1915
|
return;
|
|
1775
1916
|
if (!commissioningServer.isCommissioned()) {
|
|
1776
|
-
this.log.info(`***The commissioning server on port ${commissioningServer.getPort()} for ${plg}${pluginName}${nf} is not commissioned. Pair it scanning the QR code ...`);
|
|
1777
1917
|
const { qrPairingCode, manualPairingCode } = commissioningServer.getPairingCode();
|
|
1778
1918
|
await storageContext.set('qrPairingCode', qrPairingCode);
|
|
1779
1919
|
await storageContext.set('manualPairingCode', manualPairingCode);
|
|
1780
1920
|
await nodeContext.set('qrPairingCode', qrPairingCode);
|
|
1781
1921
|
await nodeContext.set('manualPairingCode', manualPairingCode);
|
|
1782
1922
|
const QrCode = new QrCodeSchema();
|
|
1783
|
-
this.log.info(
|
|
1923
|
+
this.log.info(`***The commissioning server on port ${commissioningServer.getPort()} for ${plg}${pluginName}${nf} is not commissioned. Pair it scanning the QR code:\n\n` +
|
|
1924
|
+
`${QrCode.encode(qrPairingCode)}\n${plg}${pluginName}${nf}\n\nqrPairingCode: ${qrPairingCode}\n\nManual pairing code: ${manualPairingCode}\n`);
|
|
1784
1925
|
if (pluginName !== 'Matterbridge') {
|
|
1785
1926
|
const plugin = this.findPlugin(pluginName);
|
|
1786
1927
|
if (plugin) {
|
|
@@ -1789,7 +1930,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
1789
1930
|
plugin.paired = false;
|
|
1790
1931
|
}
|
|
1791
1932
|
}
|
|
1792
|
-
await this.nodeContext?.set('plugins', this.getBaseRegisteredPlugins());
|
|
1933
|
+
await this.nodeContext?.set('plugins', await this.getBaseRegisteredPlugins());
|
|
1793
1934
|
}
|
|
1794
1935
|
else {
|
|
1795
1936
|
this.log.info(`*The commissioning server on port ${commissioningServer.getPort()} for ${plg}${pluginName}${nf} is already commissioned . Waiting for controllers to connect ...`);
|
|
@@ -1799,7 +1940,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
1799
1940
|
plugin.paired = true;
|
|
1800
1941
|
}
|
|
1801
1942
|
}
|
|
1802
|
-
await this.nodeContext?.set('plugins', this.getBaseRegisteredPlugins());
|
|
1943
|
+
await this.nodeContext?.set('plugins', await this.getBaseRegisteredPlugins());
|
|
1803
1944
|
}
|
|
1804
1945
|
}
|
|
1805
1946
|
/**
|
|
@@ -1875,6 +2016,9 @@ export class Matterbridge extends EventEmitter {
|
|
|
1875
2016
|
case 4937:
|
|
1876
2017
|
vendorName = '(AppleHome)';
|
|
1877
2018
|
break;
|
|
2019
|
+
case 4996:
|
|
2020
|
+
vendorName = '(AppleKeyChain)';
|
|
2021
|
+
break;
|
|
1878
2022
|
case 4362:
|
|
1879
2023
|
vendorName = '(SmartThings)';
|
|
1880
2024
|
break;
|
|
@@ -1996,7 +2140,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
1996
2140
|
}
|
|
1997
2141
|
Logger.defaultLogLevel = this.debugEnabled ? Level.DEBUG : Level.INFO;
|
|
1998
2142
|
}
|
|
1999
|
-
//logEndpoint(commissioningServer.getRootEndpoint());
|
|
2143
|
+
// logEndpoint(commissioningServer.getRootEndpoint());
|
|
2000
2144
|
}, 2000);
|
|
2001
2145
|
}
|
|
2002
2146
|
},
|
|
@@ -2023,6 +2167,48 @@ export class Matterbridge extends EventEmitter {
|
|
|
2023
2167
|
}
|
|
2024
2168
|
},
|
|
2025
2169
|
});
|
|
2170
|
+
const gdcCluster = commissioningServer.getRootClusterServer(GeneralDiagnosticsCluster);
|
|
2171
|
+
if (gdcCluster) {
|
|
2172
|
+
// We have like "30:f6:ef:69:2b:c5" in this.systemInformation.macAddress
|
|
2173
|
+
const macArray = this.systemInformation.macAddress.split(':').map((hex) => parseInt(hex, 16));
|
|
2174
|
+
let hardwareAddress = new Uint8Array(macArray);
|
|
2175
|
+
if (hardwareAddress.length === 6)
|
|
2176
|
+
hardwareAddress = Uint8Array.from([0, 0, ...hardwareAddress]);
|
|
2177
|
+
// We have like "192.168.1.189" in this.systemInformation.ipv4Address
|
|
2178
|
+
const ipv4Array = this.systemInformation.ipv4Address.split('.').map((num) => parseInt(num));
|
|
2179
|
+
const iPv4Address = new Uint8Array(ipv4Array);
|
|
2180
|
+
// We have like "fd78:cbf8:4939:746:d555:85a9:74f6:9c6" in this.systemInformation.ipv6Address
|
|
2181
|
+
const ipv6Groups = this.systemInformation.ipv6Address.split(':');
|
|
2182
|
+
const ipv6Array = [];
|
|
2183
|
+
for (const group of ipv6Groups) {
|
|
2184
|
+
const decimal = parseInt(group, 16);
|
|
2185
|
+
ipv6Array.push(decimal >> 8); // High byte
|
|
2186
|
+
ipv6Array.push(decimal & 0xff); // Low byte
|
|
2187
|
+
}
|
|
2188
|
+
const iPv6Address = new Uint8Array(ipv6Array);
|
|
2189
|
+
this.log.debug(`GeneralDiagnosticsCluster for ${plg}${pluginName}${db} hardwareAddress ${this.systemInformation.macAddress} => ${debugStringify(hardwareAddress)}`);
|
|
2190
|
+
this.log.debug(`GeneralDiagnosticsCluster for ${plg}${pluginName}${db} iPv4Address ${this.systemInformation.ipv4Address} => ${debugStringify(iPv4Address)}`);
|
|
2191
|
+
this.log.debug(`GeneralDiagnosticsCluster for ${plg}${pluginName}${db} iPv6Address ${this.systemInformation.ipv6Address} => ${debugStringify(iPv6Address)}`);
|
|
2192
|
+
try {
|
|
2193
|
+
gdcCluster.setNetworkInterfacesAttribute([
|
|
2194
|
+
{
|
|
2195
|
+
name: 'eth0',
|
|
2196
|
+
isOperational: true,
|
|
2197
|
+
offPremiseServicesReachableIPv4: null,
|
|
2198
|
+
offPremiseServicesReachableIPv6: null,
|
|
2199
|
+
hardwareAddress,
|
|
2200
|
+
iPv4Addresses: [iPv4Address],
|
|
2201
|
+
iPv6Addresses: [iPv6Address],
|
|
2202
|
+
type: GeneralDiagnostics.InterfaceType.Ethernet,
|
|
2203
|
+
},
|
|
2204
|
+
]);
|
|
2205
|
+
}
|
|
2206
|
+
catch (error) {
|
|
2207
|
+
this.log.error(`GeneralDiagnosticsCluster.setNetworkInterfacesAttribute for ${plg}${pluginName}${er} error:`, error);
|
|
2208
|
+
}
|
|
2209
|
+
}
|
|
2210
|
+
else
|
|
2211
|
+
this.log.warn(`*GeneralDiagnosticsCluster not found for ${plg}${pluginName}${wr}`);
|
|
2026
2212
|
commissioningServer.addCommandHandler('testEventTrigger', async ({ request: { enableKey, eventTrigger } }) => this.log.info(`testEventTrigger called on GeneralDiagnostic cluster: ${enableKey} ${eventTrigger}`));
|
|
2027
2213
|
return commissioningServer;
|
|
2028
2214
|
}
|
|
@@ -2049,7 +2235,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
2049
2235
|
const matterAggregator = new Aggregator();
|
|
2050
2236
|
matterAggregator.addClusterServer(ClusterServer(BasicInformationCluster, {
|
|
2051
2237
|
dataModelRevision: 1,
|
|
2052
|
-
location: '
|
|
2238
|
+
location: 'FR',
|
|
2053
2239
|
vendorId: VendorId(0xfff1),
|
|
2054
2240
|
vendorName: 'Matterbridge',
|
|
2055
2241
|
productId: 0x8000,
|
|
@@ -2058,10 +2244,10 @@ export class Matterbridge extends EventEmitter {
|
|
|
2058
2244
|
nodeLabel: 'Matterbridge aggregator',
|
|
2059
2245
|
serialNumber: await context.get('aggregatorSerialNumber'),
|
|
2060
2246
|
uniqueId: await context.get('aggregatorUniqueId'),
|
|
2061
|
-
softwareVersion: 1,
|
|
2062
|
-
softwareVersionString: '
|
|
2063
|
-
hardwareVersion: 1,
|
|
2064
|
-
hardwareVersionString: '
|
|
2247
|
+
softwareVersion: await context.get('softwareVersion', 1),
|
|
2248
|
+
softwareVersionString: await context.get('softwareVersionString', '1.0.0'),
|
|
2249
|
+
hardwareVersion: await context.get('hardwareVersion', 1),
|
|
2250
|
+
hardwareVersionString: await context.get('hardwareVersionString', '1.0.0'),
|
|
2065
2251
|
reachable: true,
|
|
2066
2252
|
capabilityMinima: { caseSessionsPerFabric: 3, subscriptionsPerFabric: 3 },
|
|
2067
2253
|
}, {}, {
|
|
@@ -2136,9 +2322,11 @@ export class Matterbridge extends EventEmitter {
|
|
|
2136
2322
|
for (const detail of interfaceDetails) {
|
|
2137
2323
|
if (detail.family === 'IPv4' && !detail.internal && this.systemInformation.ipv4Address === 'Not found') {
|
|
2138
2324
|
this.systemInformation.ipv4Address = detail.address;
|
|
2325
|
+
this.systemInformation.macAddress = detail.mac;
|
|
2139
2326
|
}
|
|
2140
2327
|
else if (detail.family === 'IPv6' && !detail.internal && this.systemInformation.ipv6Address === 'Not found') {
|
|
2141
2328
|
this.systemInformation.ipv6Address = detail.address;
|
|
2329
|
+
this.systemInformation.macAddress = detail.mac;
|
|
2142
2330
|
}
|
|
2143
2331
|
}
|
|
2144
2332
|
// Break if both addresses are found to improve efficiency
|
|
@@ -2165,6 +2353,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
2165
2353
|
this.log.debug('Host System Information:');
|
|
2166
2354
|
this.log.debug(`- Hostname: ${this.systemInformation.hostname}`);
|
|
2167
2355
|
this.log.debug(`- User: ${this.systemInformation.user}`);
|
|
2356
|
+
this.log.debug(`- MAC Address: ${this.systemInformation.macAddress}`);
|
|
2168
2357
|
this.log.debug(`- IPv4 Address: ${this.systemInformation.ipv4Address}`);
|
|
2169
2358
|
this.log.debug(`- IPv6 Address: ${this.systemInformation.ipv6Address}`);
|
|
2170
2359
|
this.log.debug(`- Node.js: ${versionMajor}.${versionMinor}.${versionPatch}`);
|
|
@@ -2280,24 +2469,30 @@ export class Matterbridge extends EventEmitter {
|
|
|
2280
2469
|
*
|
|
2281
2470
|
* @returns {BaseRegisteredPlugin[]} An array of base registered plugins.
|
|
2282
2471
|
*/
|
|
2283
|
-
getBaseRegisteredPlugins() {
|
|
2284
|
-
const baseRegisteredPlugins =
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2472
|
+
async getBaseRegisteredPlugins(includeConfigSchema = false) {
|
|
2473
|
+
const baseRegisteredPlugins = [];
|
|
2474
|
+
for (const plugin of this.registeredPlugins) {
|
|
2475
|
+
baseRegisteredPlugins.push({
|
|
2476
|
+
path: plugin.path,
|
|
2477
|
+
type: plugin.type,
|
|
2478
|
+
name: plugin.name,
|
|
2479
|
+
version: plugin.version,
|
|
2480
|
+
latestVersion: plugin.latestVersion,
|
|
2481
|
+
description: plugin.description,
|
|
2482
|
+
author: plugin.author,
|
|
2483
|
+
enabled: plugin.enabled,
|
|
2484
|
+
loaded: plugin.loaded,
|
|
2485
|
+
started: plugin.started,
|
|
2486
|
+
configured: plugin.configured,
|
|
2487
|
+
paired: plugin.paired,
|
|
2488
|
+
connected: plugin.connected,
|
|
2489
|
+
registeredDevices: plugin.registeredDevices,
|
|
2490
|
+
qrPairingCode: plugin.qrPairingCode,
|
|
2491
|
+
manualPairingCode: plugin.manualPairingCode,
|
|
2492
|
+
configJson: includeConfigSchema ? await this.loadPluginConfig(plugin) : {},
|
|
2493
|
+
schemaJson: includeConfigSchema ? await this.loadPluginSchema(plugin) : {},
|
|
2494
|
+
});
|
|
2495
|
+
}
|
|
2301
2496
|
return baseRegisteredPlugins;
|
|
2302
2497
|
}
|
|
2303
2498
|
/**
|
|
@@ -2518,9 +2713,9 @@ export class Matterbridge extends EventEmitter {
|
|
|
2518
2713
|
res.json(response);
|
|
2519
2714
|
});
|
|
2520
2715
|
// Endpoint to provide plugins
|
|
2521
|
-
this.expressApp.get('/api/plugins', (req, res) => {
|
|
2716
|
+
this.expressApp.get('/api/plugins', async (req, res) => {
|
|
2522
2717
|
this.log.debug('The frontend sent /api/plugins');
|
|
2523
|
-
res.json(this.getBaseRegisteredPlugins());
|
|
2718
|
+
res.json(await this.getBaseRegisteredPlugins(true));
|
|
2524
2719
|
});
|
|
2525
2720
|
// Endpoint to provide devices
|
|
2526
2721
|
this.expressApp.get('/api/devices', (req, res) => {
|
|
@@ -2625,7 +2820,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
2625
2820
|
res.json(data);
|
|
2626
2821
|
});
|
|
2627
2822
|
// Endpoint to receive commands
|
|
2628
|
-
this.expressApp.post('/api/command/:command/:param', async (req, res) => {
|
|
2823
|
+
this.expressApp.post('/api/command/:command/:param', express.json(), async (req, res) => {
|
|
2629
2824
|
const command = req.params.command;
|
|
2630
2825
|
let param = req.params.param;
|
|
2631
2826
|
this.log.debug(`The frontend sent /api/command/${command}/${param}`);
|
|
@@ -2642,6 +2837,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
2642
2837
|
}
|
|
2643
2838
|
// Handle the command debugLevel from Settings
|
|
2644
2839
|
if (command === 'setloglevel') {
|
|
2840
|
+
this.log.debug('setloglevel:', param);
|
|
2645
2841
|
if (param === 'Debug') {
|
|
2646
2842
|
this.log.setLogDebug(true);
|
|
2647
2843
|
this.debugEnabled = true;
|
|
@@ -2657,6 +2853,11 @@ export class Matterbridge extends EventEmitter {
|
|
|
2657
2853
|
this.debugEnabled = false;
|
|
2658
2854
|
Logger.defaultLogLevel = Level.WARN;
|
|
2659
2855
|
}
|
|
2856
|
+
else if (param === 'Error') {
|
|
2857
|
+
this.log.setLogDebug(false);
|
|
2858
|
+
this.debugEnabled = false;
|
|
2859
|
+
Logger.defaultLogLevel = Level.ERROR;
|
|
2860
|
+
}
|
|
2660
2861
|
this.registeredPlugins.forEach((plugin) => {
|
|
2661
2862
|
plugin.platform?.log.setLogDebug(this.debugEnabled);
|
|
2662
2863
|
});
|
|
@@ -2695,10 +2896,23 @@ export class Matterbridge extends EventEmitter {
|
|
|
2695
2896
|
}
|
|
2696
2897
|
this.updateProcess();
|
|
2697
2898
|
}
|
|
2899
|
+
// Handle the command saveschema from Home
|
|
2900
|
+
if (command === 'saveconfig') {
|
|
2901
|
+
param = param.replace(/\*/g, '\\');
|
|
2902
|
+
this.log.info(`Saving config for plugin ${plg}${param}${nf}...`);
|
|
2903
|
+
//console.log('Req.body:', JSON.stringify(req.body, null, 2));
|
|
2904
|
+
const plugins = await this.nodeContext?.get('plugins');
|
|
2905
|
+
if (!plugins)
|
|
2906
|
+
return;
|
|
2907
|
+
const plugin = plugins.find((plugin) => plugin.name === param);
|
|
2908
|
+
if (!plugin)
|
|
2909
|
+
return;
|
|
2910
|
+
this.savePluginConfigFromJson(plugin, req.body);
|
|
2911
|
+
}
|
|
2698
2912
|
// Handle the command installplugin from Home
|
|
2699
2913
|
if (command === 'installplugin') {
|
|
2700
2914
|
param = param.replace(/\*/g, '\\');
|
|
2701
|
-
this.log.info(`Installing plugin ${plg}${param}${
|
|
2915
|
+
this.log.info(`Installing plugin ${plg}${param}${nf}...`);
|
|
2702
2916
|
try {
|
|
2703
2917
|
await this.spawnCommand('npm', ['install', '-g', param, '--loglevel=verbose']);
|
|
2704
2918
|
this.log.info(`Plugin ${plg}${param}${nf} installed. Full restart required.`);
|
|
@@ -2710,7 +2924,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
2710
2924
|
}
|
|
2711
2925
|
}
|
|
2712
2926
|
// Handle the command addplugin from Home
|
|
2713
|
-
if (command === 'addplugin') {
|
|
2927
|
+
if (command === 'addplugin' || command === 'installplugin') {
|
|
2714
2928
|
param = param.replace(/\*/g, '\\');
|
|
2715
2929
|
if (this.registeredPlugins.find((plugin) => plugin.name === param)) {
|
|
2716
2930
|
this.log.warn(`Plugin ${plg}${param}${wr} already added to matterbridge`);
|
|
@@ -2730,7 +2944,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
2730
2944
|
const plugin = { path: packageJsonPath, type: '', name: packageJson.name, version: packageJson.version, description: packageJson.description, author: packageJson.author, enabled: true };
|
|
2731
2945
|
if (await this.loadPlugin(plugin)) {
|
|
2732
2946
|
this.registeredPlugins.push(plugin);
|
|
2733
|
-
await this.nodeContext?.set('plugins', this.getBaseRegisteredPlugins());
|
|
2947
|
+
await this.nodeContext?.set('plugins', await this.getBaseRegisteredPlugins());
|
|
2734
2948
|
this.log.info(`Plugin ${plg}${packageJsonPath}${nf} type ${plugin.type} added to matterbridge. Restart required.`);
|
|
2735
2949
|
}
|
|
2736
2950
|
else {
|
|
@@ -2749,10 +2963,10 @@ export class Matterbridge extends EventEmitter {
|
|
|
2749
2963
|
if (index !== -1) {
|
|
2750
2964
|
if (this.registeredPlugins[index].platform) {
|
|
2751
2965
|
await this.registeredPlugins[index].platform?.onShutdown('The plugin has been removed.');
|
|
2752
|
-
await this.savePluginConfig(this.registeredPlugins[index]);
|
|
2966
|
+
// await this.savePluginConfig(this.registeredPlugins[index]);
|
|
2753
2967
|
}
|
|
2754
2968
|
this.registeredPlugins.splice(index, 1);
|
|
2755
|
-
await this.nodeContext?.set('plugins', this.getBaseRegisteredPlugins());
|
|
2969
|
+
await this.nodeContext?.set('plugins', await this.getBaseRegisteredPlugins());
|
|
2756
2970
|
this.log.info(`Plugin ${plg}${param}${nf} removed from matterbridge`);
|
|
2757
2971
|
}
|
|
2758
2972
|
else {
|
|
@@ -2799,7 +3013,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
2799
3013
|
if (pluginToDisable) {
|
|
2800
3014
|
if (pluginToDisable.platform) {
|
|
2801
3015
|
await pluginToDisable.platform.onShutdown('The plugin has been removed.');
|
|
2802
|
-
await this.savePluginConfig(pluginToDisable);
|
|
3016
|
+
// await this.savePluginConfig(pluginToDisable);
|
|
2803
3017
|
}
|
|
2804
3018
|
pluginToDisable.enabled = false;
|
|
2805
3019
|
pluginToDisable.error = undefined;
|