matterbridge 1.1.4 → 1.1.5
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 +13 -0
- package/README.md +11 -9
- package/dist/matterbridge.d.ts +13 -4
- package/dist/matterbridge.d.ts.map +1 -1
- package/dist/matterbridge.js +342 -212
- package/dist/matterbridge.js.map +1 -1
- package/dist/matterbridgeAccessoryPlatform.d.ts +7 -13
- package/dist/matterbridgeAccessoryPlatform.d.ts.map +1 -1
- package/dist/matterbridgeAccessoryPlatform.js +9 -18
- package/dist/matterbridgeAccessoryPlatform.js.map +1 -1
- package/dist/matterbridgeDevice.d.ts +10 -0
- package/dist/matterbridgeDevice.d.ts.map +1 -1
- package/dist/matterbridgeDevice.js +11 -7
- package/dist/matterbridgeDevice.js.map +1 -1
- package/dist/matterbridgeDynamicPlatform.d.ts +7 -13
- package/dist/matterbridgeDynamicPlatform.d.ts.map +1 -1
- package/dist/matterbridgeDynamicPlatform.js +9 -18
- package/dist/matterbridgeDynamicPlatform.js.map +1 -1
- package/frontend/build/asset-manifest.json +3 -3
- package/frontend/build/index.html +1 -1
- package/frontend/build/manifest.json +2 -2
- package/frontend/build/matterbridge 32x32.png +0 -0
- package/frontend/build/matterbridge 64x64.png +0 -0
- package/frontend/build/static/js/{main.b5a876cf.js → main.b6ca1c6b.js} +3 -3
- package/frontend/build/static/js/main.b6ca1c6b.js.map +1 -0
- package/package.json +3 -2
- package/frontend/build/static/js/main.b5a876cf.js.map +0 -1
- /package/frontend/build/static/js/{main.b5a876cf.js.LICENSE.txt → main.b6ca1c6b.js.LICENSE.txt} +0 -0
package/dist/matterbridge.js
CHANGED
|
@@ -20,8 +20,9 @@
|
|
|
20
20
|
* See the License for the specific language governing permissions and
|
|
21
21
|
* limitations under the License. *
|
|
22
22
|
*/
|
|
23
|
+
import { MatterbridgeDevice } from './matterbridgeDevice.js';
|
|
23
24
|
import { NodeStorageManager } from 'node-persist-manager';
|
|
24
|
-
import { AnsiLogger, BRIGHT,
|
|
25
|
+
import { AnsiLogger, BRIGHT, RESET, UNDERLINE, UNDERLINEOFF, YELLOW, db, debugStringify, stringify, er, nf, rs, wr } from 'node-ansi-logger';
|
|
25
26
|
import { fileURLToPath, pathToFileURL } from 'url';
|
|
26
27
|
import { promises as fs } from 'fs';
|
|
27
28
|
import express from 'express';
|
|
@@ -38,6 +39,7 @@ import { requireMinNodeVersion, getParameter, getIntParameter, hasParameter } fr
|
|
|
38
39
|
import { CryptoNode } from '@project-chip/matter-node.js/crypto';
|
|
39
40
|
const plg = '\u001B[38;5;33m';
|
|
40
41
|
const dev = '\u001B[38;5;79m';
|
|
42
|
+
const typ = '\u001B[38;5;207m';
|
|
41
43
|
/**
|
|
42
44
|
* Represents the Matterbridge application.
|
|
43
45
|
*/
|
|
@@ -55,16 +57,18 @@ export class Matterbridge {
|
|
|
55
57
|
freeMemory: '',
|
|
56
58
|
systemUptime: '',
|
|
57
59
|
};
|
|
58
|
-
homeDirectory;
|
|
59
|
-
rootDirectory;
|
|
60
|
-
matterbridgeDirectory;
|
|
60
|
+
homeDirectory = '';
|
|
61
|
+
rootDirectory = '';
|
|
62
|
+
matterbridgeDirectory = '';
|
|
63
|
+
matterbridgeVersion = '';
|
|
61
64
|
bridgeMode = '';
|
|
65
|
+
debugEnabled = false;
|
|
62
66
|
log;
|
|
63
67
|
hasCleanupStarted = false;
|
|
64
68
|
registeredPlugins = [];
|
|
65
69
|
registeredDevices = [];
|
|
66
|
-
nodeStorage
|
|
67
|
-
nodeContext
|
|
70
|
+
nodeStorage;
|
|
71
|
+
nodeContext;
|
|
68
72
|
app;
|
|
69
73
|
storageManager;
|
|
70
74
|
matterbridgeContext;
|
|
@@ -79,7 +83,7 @@ export class Matterbridge {
|
|
|
79
83
|
}
|
|
80
84
|
/**
|
|
81
85
|
* Loads an instance of the Matterbridge class.
|
|
82
|
-
* If an instance already exists,
|
|
86
|
+
* If an instance already exists, return that instance.
|
|
83
87
|
* @returns The loaded instance of the Matterbridge class.
|
|
84
88
|
*/
|
|
85
89
|
static async loadInstance(cli = false) {
|
|
@@ -118,6 +122,7 @@ export class Matterbridge {
|
|
|
118
122
|
- bridge: start Matterbridge in bridge mode
|
|
119
123
|
- childbridge: start Matterbridge in childbridge mode
|
|
120
124
|
- frontend [port]: start the frontend on the given port (default 3000)
|
|
125
|
+
- debug: enable debug mode (default false)
|
|
121
126
|
- list: list the registered plugins
|
|
122
127
|
- add [plugin path]: register the plugin
|
|
123
128
|
- remove [plugin path]: remove the plugin
|
|
@@ -126,29 +131,38 @@ export class Matterbridge {
|
|
|
126
131
|
process.exit(0);
|
|
127
132
|
}
|
|
128
133
|
// set Matterbridge logger
|
|
129
|
-
|
|
130
|
-
|
|
134
|
+
if (hasParameter('debug'))
|
|
135
|
+
this.debugEnabled = true;
|
|
136
|
+
this.log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logDebug: this.debugEnabled });
|
|
137
|
+
this.log.debug('Matterbridge is starting...');
|
|
131
138
|
// log system info and create .matterbridge directory
|
|
132
139
|
await this.logNodeAndSystemInfo();
|
|
140
|
+
this.log.info(
|
|
141
|
+
// eslint-disable-next-line max-len
|
|
142
|
+
`Matterbridge version ${this.matterbridgeVersion} mode ${hasParameter('bridge') ? 'bridge' : ''}${hasParameter('childbridge') ? 'childbridge' : ''} running on ${this.systemInformation.osType} ${this.systemInformation.osRelease} ${this.systemInformation.osPlatform} ${this.systemInformation.osArch}`);
|
|
133
143
|
// check node version and throw error
|
|
134
144
|
requireMinNodeVersion(18);
|
|
135
145
|
// register SIGINT SIGTERM signal handlers
|
|
136
146
|
this.registerSignalHandlers();
|
|
137
147
|
// set matter.js logger level and format
|
|
138
|
-
Logger.defaultLogLevel = Level.DEBUG;
|
|
148
|
+
Logger.defaultLogLevel = this.debugEnabled ? Level.DEBUG : Level.INFO;
|
|
139
149
|
Logger.format = Format.ANSI;
|
|
140
150
|
// Initialize NodeStorage
|
|
141
151
|
this.log.debug('Creating node storage manager');
|
|
142
|
-
this.nodeStorage = new NodeStorageManager({ dir: path.join(this.matterbridgeDirectory, 'storage') });
|
|
152
|
+
this.nodeStorage = new NodeStorageManager({ dir: path.join(this.matterbridgeDirectory, 'storage'), logging: false });
|
|
143
153
|
this.log.debug('Creating node storage context for matterbridge');
|
|
144
154
|
this.nodeContext = await this.nodeStorage.createStorage('matterbridge');
|
|
145
155
|
this.registeredPlugins = await this.nodeContext.get('plugins', []);
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
156
|
+
for (const plugin of this.registeredPlugins) {
|
|
157
|
+
this.log.debug(`Creating node storage context for plugin ${plugin.name}`);
|
|
158
|
+
plugin.nodeContext = await this.nodeStorage?.createStorage(plugin.name);
|
|
159
|
+
await plugin.nodeContext?.set('name', plugin.name);
|
|
160
|
+
await plugin.nodeContext?.set('type', plugin.type);
|
|
161
|
+
await plugin.nodeContext?.set('path', plugin.path);
|
|
162
|
+
await plugin.nodeContext?.set('version', plugin.version);
|
|
163
|
+
await plugin.nodeContext?.set('description', plugin.description);
|
|
164
|
+
await plugin.nodeContext?.set('author', plugin.author);
|
|
165
|
+
}
|
|
152
166
|
// Parse command line
|
|
153
167
|
this.parseCommandLine();
|
|
154
168
|
}
|
|
@@ -161,30 +175,28 @@ export class Matterbridge {
|
|
|
161
175
|
if (hasParameter('list')) {
|
|
162
176
|
this.log.info('Registered plugins:');
|
|
163
177
|
this.registeredPlugins.forEach((plugin) => {
|
|
164
|
-
this.log.info(`- ${plg}${plugin.name}${nf}: "${plg}${BRIGHT}${plugin.description}${RESET}${nf}"
|
|
165
|
-
` author: "${plugin.author}" type: ${GREEN}${plugin.type}${nf} ${YELLOW}${plugin.enabled ? 'enabled' : 'disabled'}${nf}`);
|
|
166
|
-
// loaded: ${plugin.loaded} started: ${plugin.started} paired: ${plugin.paired} connected: ${plugin.connected}
|
|
178
|
+
this.log.info(`- ${plg}${plugin.name}${nf}: "${plg}${BRIGHT}${plugin.description}${RESET}${nf}" type: ${typ}${plugin.type}${nf} ${YELLOW}${plugin.enabled ? 'enabled' : 'disabled'}${nf}`);
|
|
167
179
|
});
|
|
168
180
|
process.exit(0);
|
|
169
181
|
}
|
|
170
182
|
if (getParameter('add')) {
|
|
171
183
|
this.log.debug(`Registering plugin ${getParameter('add')}`);
|
|
172
|
-
await this.
|
|
184
|
+
await this.executeCommandLine(getParameter('add'), 'add');
|
|
173
185
|
process.exit(0);
|
|
174
186
|
}
|
|
175
187
|
if (getParameter('remove')) {
|
|
176
188
|
this.log.debug(`Unregistering plugin ${getParameter('remove')}`);
|
|
177
|
-
await this.
|
|
189
|
+
await this.executeCommandLine(getParameter('remove'), 'remove');
|
|
178
190
|
process.exit(0);
|
|
179
191
|
}
|
|
180
192
|
if (getParameter('enable')) {
|
|
181
193
|
this.log.debug(`Enable plugin ${getParameter('enable')}`);
|
|
182
|
-
await this.
|
|
194
|
+
await this.executeCommandLine(getParameter('enable'), 'enable');
|
|
183
195
|
process.exit(0);
|
|
184
196
|
}
|
|
185
197
|
if (getParameter('disable')) {
|
|
186
198
|
this.log.debug(`Disable plugin ${getParameter('disable')}`);
|
|
187
|
-
await this.
|
|
199
|
+
await this.executeCommandLine(getParameter('disable'), 'disable');
|
|
188
200
|
process.exit(0);
|
|
189
201
|
}
|
|
190
202
|
// Start the storage (we need it now for frontend and later for matterbridge)
|
|
@@ -193,128 +205,96 @@ export class Matterbridge {
|
|
|
193
205
|
this.matterbridgeContext = this.createCommissioningServerContext('Matterbridge', 'Matterbridge', DeviceTypes.AGGREGATOR.code, 0xfff1, 'Matterbridge', 0x8000, 'Matterbridge aggregator');
|
|
194
206
|
// Initialize frontend
|
|
195
207
|
await this.initializeFrontend(getIntParameter('frontend'));
|
|
196
|
-
if (hasParameter('
|
|
208
|
+
if (hasParameter('test')) {
|
|
197
209
|
this.bridgeMode = 'childbridge';
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
return;
|
|
201
|
-
this.log.info(`Loading registered plugin ${plg}${plugin.name}${nf} type ${GREEN}${plugin.type}${nf}`);
|
|
202
|
-
await this.loadPlugin(plugin.path, 'load');
|
|
203
|
-
});
|
|
204
|
-
await this.startMatterBridge();
|
|
210
|
+
MatterbridgeDevice.bridgeMode = 'childbridge';
|
|
211
|
+
this.testStartMatterBridge(); // No await do it asyncronously
|
|
205
212
|
}
|
|
206
213
|
if (hasParameter('bridge')) {
|
|
207
214
|
this.bridgeMode = 'bridge';
|
|
208
|
-
|
|
215
|
+
MatterbridgeDevice.bridgeMode = 'bridge';
|
|
216
|
+
for (const plugin of this.registeredPlugins) {
|
|
209
217
|
if (!plugin.enabled)
|
|
210
|
-
|
|
211
|
-
this.
|
|
212
|
-
|
|
213
|
-
|
|
218
|
+
continue;
|
|
219
|
+
this.loadPlugin(plugin); // No await do it asyncronously
|
|
220
|
+
}
|
|
221
|
+
await this.startMatterBridge();
|
|
222
|
+
}
|
|
223
|
+
if (hasParameter('childbridge')) {
|
|
224
|
+
this.bridgeMode = 'childbridge';
|
|
225
|
+
MatterbridgeDevice.bridgeMode = 'childbridge';
|
|
226
|
+
for (const plugin of this.registeredPlugins) {
|
|
227
|
+
if (!plugin.enabled)
|
|
228
|
+
continue;
|
|
229
|
+
this.loadPlugin(plugin); // No await do it asyncronously
|
|
230
|
+
}
|
|
214
231
|
await this.startMatterBridge();
|
|
215
232
|
}
|
|
216
233
|
}
|
|
217
234
|
/**
|
|
218
235
|
* Loads a plugin from the specified package.json file path.
|
|
219
236
|
* @param packageJsonPath - The path to the package.json file of the plugin.
|
|
220
|
-
* @param mode - The mode of operation. Possible values are '
|
|
237
|
+
* @param mode - The mode of operation. Possible values are 'add', 'remove', 'enable', 'disable'.
|
|
221
238
|
* @returns A Promise that resolves when the plugin is loaded successfully, or rejects with an error if loading fails.
|
|
222
239
|
*/
|
|
223
|
-
async
|
|
240
|
+
async executeCommandLine(packageJsonPath, mode) {
|
|
224
241
|
if (!packageJsonPath.endsWith('package.json'))
|
|
225
242
|
packageJsonPath = path.join(packageJsonPath, 'package.json');
|
|
243
|
+
// Resolve the package.json of the plugin
|
|
226
244
|
packageJsonPath = path.resolve(packageJsonPath);
|
|
227
245
|
this.log.debug(`Loading plugin from ${plg}${packageJsonPath}${db}`);
|
|
228
246
|
try {
|
|
229
247
|
// Load the package.json of the plugin
|
|
230
248
|
const packageJson = JSON.parse(await fs.readFile(packageJsonPath, 'utf8'));
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
const pluginUrl = pathToFileURL(pluginPath);
|
|
239
|
-
// Dynamically import the plugin
|
|
240
|
-
this.log.debug(`Importing plugin ${plg}${plugin?.name}${db} from ${pluginUrl.href}`);
|
|
241
|
-
const pluginInstance = await import(pluginUrl.href);
|
|
242
|
-
this.log.debug(`Imported plugin ${plg}${plugin?.name}${db} from ${pluginUrl.href}`);
|
|
243
|
-
// Call the default export function of the plugin, passing this MatterBridge instance
|
|
244
|
-
if (pluginInstance.default) {
|
|
245
|
-
const platform = pluginInstance.default(this, new AnsiLogger({ logName: packageJson.description, logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */ }));
|
|
246
|
-
platform.name = packageJson.name;
|
|
247
|
-
if (mode === 'load') {
|
|
248
|
-
this.log.info(`Plugin ${plg}${plugin?.name}${nf} type ${GREEN}${platform.type}${nf} loaded (entrypoint ${UNDERLINE}${pluginPath}${UNDERLINEOFF})`);
|
|
249
|
-
// Update plugin info
|
|
250
|
-
if (plugin) {
|
|
251
|
-
plugin.path = packageJsonPath;
|
|
252
|
-
plugin.name = packageJson.name;
|
|
253
|
-
plugin.description = packageJson.description;
|
|
254
|
-
plugin.version = packageJson.version;
|
|
255
|
-
plugin.author = packageJson.author;
|
|
256
|
-
plugin.type = platform.type;
|
|
257
|
-
plugin.loaded = true;
|
|
258
|
-
plugin.platform = platform;
|
|
249
|
+
if (mode === 'add') {
|
|
250
|
+
if (!this.registeredPlugins.find((plugin) => plugin.name === packageJson.name)) {
|
|
251
|
+
const plugin = { path: packageJsonPath, type: '', name: packageJson.name, version: packageJson.version, description: packageJson.description, author: packageJson.author, enabled: true };
|
|
252
|
+
if (await this.loadPlugin(plugin)) {
|
|
253
|
+
this.registeredPlugins.push(plugin);
|
|
254
|
+
await this.nodeContext?.set('plugins', this.getBaseRegisteredPlugins());
|
|
255
|
+
this.log.info(`Plugin ${plg}${packageJsonPath}${nf} type ${plugin.type} added to matterbridge`);
|
|
259
256
|
}
|
|
260
257
|
else {
|
|
261
|
-
this.log.error(`Plugin ${plg}${
|
|
258
|
+
this.log.error(`Plugin ${plg}${packageJsonPath}${wr} not added to matterbridge error`);
|
|
262
259
|
}
|
|
263
260
|
}
|
|
264
|
-
else
|
|
265
|
-
|
|
266
|
-
this.registeredPlugins.push({
|
|
267
|
-
path: packageJsonPath,
|
|
268
|
-
type: platform.type,
|
|
269
|
-
name: packageJson.name,
|
|
270
|
-
version: packageJson.version,
|
|
271
|
-
description: packageJson.description,
|
|
272
|
-
author: packageJson.author,
|
|
273
|
-
enabled: true,
|
|
274
|
-
});
|
|
275
|
-
await this.nodeContext?.set('plugins', this.registeredPlugins);
|
|
276
|
-
this.log.info(`Plugin ${plg}${packageJsonPath}${nf} type ${platform.type} added to matterbridge`);
|
|
277
|
-
}
|
|
278
|
-
else {
|
|
279
|
-
this.log.warn(`Plugin ${plg}${packageJsonPath}${wr} already added to matterbridge`);
|
|
280
|
-
}
|
|
261
|
+
else {
|
|
262
|
+
this.log.warn(`Plugin ${plg}${packageJsonPath}${wr} already added to matterbridge`);
|
|
281
263
|
}
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
}
|
|
288
|
-
else {
|
|
289
|
-
this.log.warn(`Plugin ${plg}${packageJsonPath}${wr} not registerd in matterbridge`);
|
|
290
|
-
}
|
|
264
|
+
}
|
|
265
|
+
else if (mode === 'remove') {
|
|
266
|
+
if (this.registeredPlugins.find((registeredPlugin) => registeredPlugin.name === packageJson.name)) {
|
|
267
|
+
this.registeredPlugins.splice(this.registeredPlugins.findIndex((registeredPlugin) => registeredPlugin.name === packageJson.name), 1);
|
|
268
|
+
await this.nodeContext?.set('plugins', this.getBaseRegisteredPlugins());
|
|
269
|
+
this.log.info(`Plugin ${plg}${packageJsonPath}${nf} removed from matterbridge`);
|
|
291
270
|
}
|
|
292
|
-
else
|
|
293
|
-
|
|
294
|
-
if (plugin) {
|
|
295
|
-
plugin.enabled = true;
|
|
296
|
-
await this.nodeContext?.set('plugins', this.registeredPlugins);
|
|
297
|
-
this.log.info(`Plugin ${plg}${packageJsonPath}${nf} enabled`);
|
|
298
|
-
}
|
|
299
|
-
else {
|
|
300
|
-
this.log.warn(`Plugin ${plg}${packageJsonPath}${wr} not registerd in matterbridge`);
|
|
301
|
-
}
|
|
271
|
+
else {
|
|
272
|
+
this.log.warn(`Plugin ${plg}${packageJsonPath}${wr} not registerd in matterbridge`);
|
|
302
273
|
}
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
}
|
|
310
|
-
else {
|
|
311
|
-
this.log.warn(`Plugin ${plg}${packageJsonPath}${wr} not registerd in matterbridge`);
|
|
312
|
-
}
|
|
274
|
+
}
|
|
275
|
+
else if (mode === 'enable') {
|
|
276
|
+
const plugin = this.registeredPlugins.find((registeredPlugin) => registeredPlugin.name === packageJson.name);
|
|
277
|
+
if (plugin) {
|
|
278
|
+
plugin.enabled = true;
|
|
279
|
+
await this.nodeContext?.set('plugins', this.getBaseRegisteredPlugins());
|
|
280
|
+
this.log.info(`Plugin ${plg}${packageJsonPath}${nf} enabled`);
|
|
313
281
|
}
|
|
314
282
|
else {
|
|
315
|
-
this.log.
|
|
283
|
+
this.log.warn(`Plugin ${plg}${packageJsonPath}${wr} not registerd in matterbridge`);
|
|
316
284
|
}
|
|
317
285
|
}
|
|
286
|
+
else if (mode === 'disable') {
|
|
287
|
+
const plugin = this.registeredPlugins.find((registeredPlugin) => registeredPlugin.name === packageJson.name);
|
|
288
|
+
if (plugin) {
|
|
289
|
+
plugin.enabled = false;
|
|
290
|
+
await this.nodeContext?.set('plugins', this.getBaseRegisteredPlugins());
|
|
291
|
+
this.log.info(`Plugin ${plg}${packageJsonPath}${nf} disabled`);
|
|
292
|
+
}
|
|
293
|
+
else {
|
|
294
|
+
this.log.warn(`Plugin ${plg}${packageJsonPath}${wr} not registerd in matterbridge`);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
//}
|
|
318
298
|
}
|
|
319
299
|
catch (err) {
|
|
320
300
|
this.log.error(`Failed to load plugin from ${plg}${packageJsonPath}${er}: ${err}`);
|
|
@@ -339,13 +319,12 @@ export class Matterbridge {
|
|
|
339
319
|
async cleanup(message) {
|
|
340
320
|
if (!this.hasCleanupStarted) {
|
|
341
321
|
this.hasCleanupStarted = true;
|
|
342
|
-
this.log.
|
|
322
|
+
this.log.info(message);
|
|
343
323
|
// Callint the shutdown functions with a reason
|
|
344
|
-
this.registeredPlugins
|
|
345
|
-
if (plugin.platform)
|
|
346
|
-
plugin.platform.onShutdown('Matterbridge is closing: ' + message);
|
|
347
|
-
|
|
348
|
-
});
|
|
324
|
+
for (const plugin of this.registeredPlugins) {
|
|
325
|
+
if (plugin.platform)
|
|
326
|
+
await plugin.platform.onShutdown('Matterbridge is closing: ' + message);
|
|
327
|
+
}
|
|
349
328
|
// Set reachability to false
|
|
350
329
|
/*
|
|
351
330
|
this.log.debug(`*Changing reachability to false for ${this.registeredDevices.length} devices (${this.bridgeMode} mode):`);
|
|
@@ -368,10 +347,15 @@ export class Matterbridge {
|
|
|
368
347
|
await this.stopMatter();
|
|
369
348
|
// Closing storage
|
|
370
349
|
await this.stopStorage();
|
|
371
|
-
|
|
372
|
-
this.
|
|
350
|
+
const serializedRegisteredDevices = [];
|
|
351
|
+
this.registeredDevices.forEach((registeredDevice) => {
|
|
352
|
+
serializedRegisteredDevices.push(registeredDevice.device.serialize(registeredDevice.plugin));
|
|
353
|
+
});
|
|
354
|
+
//console.log('serializedRegisteredDevices:', serializedRegisteredDevices);
|
|
355
|
+
await this.nodeContext?.set('devices', serializedRegisteredDevices);
|
|
356
|
+
this.log.info('Cleanup completed.');
|
|
373
357
|
process.exit(0);
|
|
374
|
-
},
|
|
358
|
+
}, 3 * 1000);
|
|
375
359
|
}
|
|
376
360
|
}
|
|
377
361
|
/**
|
|
@@ -392,6 +376,7 @@ export class Matterbridge {
|
|
|
392
376
|
* Adds a device to the Matterbridge.
|
|
393
377
|
* @param pluginName - The name of the plugin.
|
|
394
378
|
* @param device - The device to be added.
|
|
379
|
+
* @returns A Promise that resolves when the device is added successfully.
|
|
395
380
|
*/
|
|
396
381
|
async addDevice(pluginName, device) {
|
|
397
382
|
this.log.info(`Adding device ${dev}${device.name}${nf} for plugin ${plg}${pluginName}${nf}`);
|
|
@@ -403,20 +388,19 @@ export class Matterbridge {
|
|
|
403
388
|
}
|
|
404
389
|
// Add and register the device to the matterbridge in bridge mode
|
|
405
390
|
if (this.bridgeMode === 'bridge') {
|
|
406
|
-
const basic = device.getClusterServerById(BasicInformationCluster.id);
|
|
407
|
-
if (!basic) {
|
|
408
|
-
this.log.error(`addDevice error: cannot find the BasicInformationCluster device ${dev}${device.name}${nf} plugin ${plg}${pluginName}${nf}`);
|
|
409
|
-
return;
|
|
410
|
-
}
|
|
411
|
-
device.createDefaultBridgedDeviceBasicInformationClusterServer(basic.getNodeLabelAttribute(), basic.getSerialNumberAttribute(), basic.getVendorIdAttribute(), basic.getVendorNameAttribute(), basic.getProductNameAttribute(), basic.getSoftwareVersionAttribute(), basic.getSoftwareVersionStringAttribute(), basic.getHardwareVersionAttribute(), basic.getHardwareVersionStringAttribute());
|
|
412
|
-
//console.log(basic.getSoftwareVersionAttribute(), basic.getSoftwareVersionStringAttribute());
|
|
413
391
|
this.matterAggregator.addBridgedDevice(device);
|
|
414
392
|
this.registeredDevices.push({ plugin: pluginName, device, added: true });
|
|
415
|
-
|
|
393
|
+
if (plugin.registeredDevices !== undefined)
|
|
394
|
+
plugin.registeredDevices++;
|
|
395
|
+
if (plugin.addedDevices !== undefined)
|
|
396
|
+
plugin.addedDevices++;
|
|
397
|
+
this.log.info(`Added and registered device(${plugin.registeredDevices}/${plugin.addedDevices}) ${dev}${device.name}${nf} for plugin ${plg}${pluginName}${nf}`);
|
|
416
398
|
}
|
|
417
399
|
// Only register the device in childbridge mode
|
|
418
400
|
if (this.bridgeMode === 'childbridge') {
|
|
419
401
|
this.registeredDevices.push({ plugin: pluginName, device, added: false });
|
|
402
|
+
if (plugin.registeredDevices !== undefined)
|
|
403
|
+
plugin.registeredDevices++;
|
|
420
404
|
this.log.info(`Registered device ${dev}${device.name}${nf} for plugin ${plg}${pluginName}${nf}`);
|
|
421
405
|
}
|
|
422
406
|
}
|
|
@@ -424,6 +408,7 @@ export class Matterbridge {
|
|
|
424
408
|
* Adds a bridged device to the Matterbridge.
|
|
425
409
|
* @param pluginName - The name of the plugin.
|
|
426
410
|
* @param device - The bridged device to add.
|
|
411
|
+
* @returns {Promise<void>} - A promise that resolves when the storage process is started.
|
|
427
412
|
*/
|
|
428
413
|
async addBridgedDevice(pluginName, device) {
|
|
429
414
|
this.log.info(`Adding bridged device ${dev}${device.name}${nf} for plugin ${plg}${pluginName}${nf}`);
|
|
@@ -437,14 +422,18 @@ export class Matterbridge {
|
|
|
437
422
|
if (this.bridgeMode === 'bridge') {
|
|
438
423
|
this.matterAggregator.addBridgedDevice(device);
|
|
439
424
|
this.registeredDevices.push({ plugin: pluginName, device, added: true });
|
|
440
|
-
|
|
425
|
+
if (plugin.registeredDevices !== undefined)
|
|
426
|
+
plugin.registeredDevices++;
|
|
427
|
+
if (plugin.addedDevices !== undefined)
|
|
428
|
+
plugin.addedDevices++;
|
|
429
|
+
this.log.info(`Added and registered bridged device(${plugin.registeredDevices}/${plugin.addedDevices}) ${dev}${device.name}${nf} for plugin ${plg}${pluginName}${nf}`);
|
|
441
430
|
}
|
|
442
431
|
// Only register the device in childbridge mode
|
|
443
432
|
if (this.bridgeMode === 'childbridge') {
|
|
444
433
|
this.registeredDevices.push({ plugin: pluginName, device, added: false });
|
|
434
|
+
if (plugin.registeredDevices !== undefined)
|
|
435
|
+
plugin.registeredDevices++;
|
|
445
436
|
this.log.info(`Registered bridged device ${dev}${device.name}${nf} for plugin ${plg}${pluginName}${nf}`);
|
|
446
|
-
//const basic = device.getClusterServerById(BridgedDeviceBasicInformationCluster.id);
|
|
447
|
-
//console.log(JSON.stringify(basic, null, 2));
|
|
448
437
|
}
|
|
449
438
|
}
|
|
450
439
|
/**
|
|
@@ -513,6 +502,144 @@ export class Matterbridge {
|
|
|
513
502
|
await this.storageManager.close();
|
|
514
503
|
this.log.debug('Storage closed');
|
|
515
504
|
}
|
|
505
|
+
async testStartMatterBridge() {
|
|
506
|
+
for (const plugin of this.registeredPlugins) {
|
|
507
|
+
if (!plugin.enabled)
|
|
508
|
+
continue;
|
|
509
|
+
// No await do it asyncronously
|
|
510
|
+
this.loadPlugin(plugin)
|
|
511
|
+
.then(() => {
|
|
512
|
+
// No await do it asyncronously
|
|
513
|
+
this.startPlugin(plugin)
|
|
514
|
+
.then(() => { })
|
|
515
|
+
.catch((err) => {
|
|
516
|
+
this.log.error(`Failed to start plugin ${plg}${plugin.name}${er}: ${err}`);
|
|
517
|
+
});
|
|
518
|
+
})
|
|
519
|
+
.catch((err) => {
|
|
520
|
+
this.log.error(`Failed to load plugin ${plg}${plugin.name}${er}: ${err}`);
|
|
521
|
+
});
|
|
522
|
+
}
|
|
523
|
+
for (const plugin of this.registeredPlugins) {
|
|
524
|
+
if (!plugin.enabled)
|
|
525
|
+
continue;
|
|
526
|
+
// Start the interval to check if the plugin is loaded and started
|
|
527
|
+
let times = 0;
|
|
528
|
+
const interval = setInterval(() => {
|
|
529
|
+
times++;
|
|
530
|
+
this.log.info(`Waiting ${times} secs for plugin ${plg}${plugin.name}${db} to load (${plugin.loaded}) and start (${plugin.started}) and send devices ...`);
|
|
531
|
+
if (!plugin.loaded || !plugin.started)
|
|
532
|
+
return;
|
|
533
|
+
this.log.info(`Plugin ${plg}${plugin.name}${db} sent ${plugin.registeredDevices} devices`);
|
|
534
|
+
clearInterval(interval);
|
|
535
|
+
}, 1000);
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
async startPlugin(plugin, message, configure = false) {
|
|
539
|
+
if (!plugin.loaded || !plugin.platform) {
|
|
540
|
+
this.log.error(`Plugin ${plg}${plugin.name}${er} not loaded or no platform`);
|
|
541
|
+
return Promise.reject(new Error(`Plugin ${plg}${plugin.name}${er} not loaded or no platform`));
|
|
542
|
+
}
|
|
543
|
+
if (plugin.started) {
|
|
544
|
+
this.log.error(`Plugin ${plg}${plugin.name}${er} already started`);
|
|
545
|
+
return Promise.resolve();
|
|
546
|
+
}
|
|
547
|
+
this.log.info(`Starting plugin ${plg}${plugin.name}${db} type ${typ}${plugin.type}${db}`);
|
|
548
|
+
try {
|
|
549
|
+
plugin.platform
|
|
550
|
+
.onStart(message)
|
|
551
|
+
.then(() => {
|
|
552
|
+
plugin.started = true;
|
|
553
|
+
this.log.info(`Started plugin ${plg}${plugin.name}${db} type ${typ}${plugin.type}${db}`);
|
|
554
|
+
if (configure)
|
|
555
|
+
this.configurePlugin(plugin); // No await do it asyncronously
|
|
556
|
+
return Promise.resolve();
|
|
557
|
+
})
|
|
558
|
+
.catch((err) => {
|
|
559
|
+
this.log.error(`Failed to start plugin ${plg}${plugin.name}${er}: ${err}`);
|
|
560
|
+
return Promise.reject(new Error(`Failed to start plugin ${plg}${plugin.name}${er}: ${err}`));
|
|
561
|
+
});
|
|
562
|
+
}
|
|
563
|
+
catch (err) {
|
|
564
|
+
this.log.error(`Failed to start plugin ${plg}${plugin.name}${er}: ${err}`);
|
|
565
|
+
return Promise.reject(new Error(`Failed to start plugin ${plg}${plugin.name}${er}: ${err}`));
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
async configurePlugin(plugin) {
|
|
569
|
+
if (!plugin.loaded || !plugin.started || !plugin.platform) {
|
|
570
|
+
this.log.error(`Plugin ${plg}${plugin.name}${er} not loaded or not started or not platform`);
|
|
571
|
+
return Promise.reject(new Error(`Plugin ${plg}${plugin.name}${er} not loaded or not started or not platform`));
|
|
572
|
+
}
|
|
573
|
+
if (plugin.configured) {
|
|
574
|
+
this.log.error(`Plugin ${plg}${plugin.name}${er} already configured`);
|
|
575
|
+
return Promise.resolve();
|
|
576
|
+
}
|
|
577
|
+
this.log.info(`Configuring plugin ${plg}${plugin.name}${db} type ${typ}${plugin.type}${db}`);
|
|
578
|
+
try {
|
|
579
|
+
plugin.platform
|
|
580
|
+
.onConfigure()
|
|
581
|
+
.then(() => {
|
|
582
|
+
plugin.configured = true;
|
|
583
|
+
this.log.info(`Configured plugin ${plg}${plugin.name}${db} type ${typ}${plugin.type}${db}`);
|
|
584
|
+
return Promise.resolve();
|
|
585
|
+
})
|
|
586
|
+
.catch((err) => {
|
|
587
|
+
this.log.error(`Failed to configure plugin ${plg}${plugin.name}${er}: ${err}`);
|
|
588
|
+
return Promise.reject(new Error(`Failed to configure plugin ${plg}${plugin.name}${er}: ${err}`));
|
|
589
|
+
});
|
|
590
|
+
}
|
|
591
|
+
catch (err) {
|
|
592
|
+
this.log.error(`Failed to configure plugin ${plg}${plugin.name}${er}: ${err}`);
|
|
593
|
+
return Promise.reject(new Error(`Failed to configure plugin ${plg}${plugin.name}${er}: ${err}`));
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
async loadPlugin(plugin) {
|
|
597
|
+
if (!plugin.enabled) {
|
|
598
|
+
this.log.error(`Plugin ${plg}${plugin.name}${er} not enabled`);
|
|
599
|
+
return Promise.reject(new Error(`Plugin ${plg}${plugin.name}${er} not enabled`));
|
|
600
|
+
}
|
|
601
|
+
if (plugin.platform) {
|
|
602
|
+
this.log.error(`Plugin ${plg}${plugin.name}${er} already loaded`);
|
|
603
|
+
return Promise.resolve(plugin.platform);
|
|
604
|
+
}
|
|
605
|
+
this.log.info(`Loading plugin ${plg}${plugin.name}${db} type ${typ}${plugin.type}${db}`);
|
|
606
|
+
try {
|
|
607
|
+
// Load the package.json of the plugin
|
|
608
|
+
const packageJson = JSON.parse(await fs.readFile(plugin.path, 'utf8'));
|
|
609
|
+
// Resolve the main module path relative to package.json
|
|
610
|
+
const pluginEntry = path.resolve(path.dirname(plugin.path), packageJson.main);
|
|
611
|
+
// Dynamically import the plugin
|
|
612
|
+
const pluginUrl = pathToFileURL(pluginEntry);
|
|
613
|
+
this.log.debug(`Importing plugin ${plg}${plugin.name}${db} from ${pluginUrl.href}`);
|
|
614
|
+
const pluginInstance = await import(pluginUrl.href);
|
|
615
|
+
this.log.debug(`Imported plugin ${plg}${plugin.name}${db} from ${pluginUrl.href}`);
|
|
616
|
+
// Call the default export function of the plugin, passing this MatterBridge instance
|
|
617
|
+
if (pluginInstance.default) {
|
|
618
|
+
const platform = pluginInstance.default(this, new AnsiLogger({ logName: plugin.description, logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logDebug: this.debugEnabled }));
|
|
619
|
+
platform.name = packageJson.name;
|
|
620
|
+
plugin.name = packageJson.name;
|
|
621
|
+
plugin.description = packageJson.description;
|
|
622
|
+
plugin.version = packageJson.version;
|
|
623
|
+
plugin.author = packageJson.author;
|
|
624
|
+
plugin.type = platform.type;
|
|
625
|
+
plugin.platform = platform;
|
|
626
|
+
plugin.loaded = true;
|
|
627
|
+
plugin.registeredDevices = 0;
|
|
628
|
+
plugin.addedDevices = 0;
|
|
629
|
+
await this.nodeContext?.set('plugins', this.getBaseRegisteredPlugins());
|
|
630
|
+
this.log.info(`Loaded plugin ${plg}${plugin.name}${db} type ${typ}${platform.type}${db} (entrypoint ${UNDERLINE}${pluginEntry}${UNDERLINEOFF})`);
|
|
631
|
+
return Promise.resolve(platform);
|
|
632
|
+
}
|
|
633
|
+
else {
|
|
634
|
+
this.log.error(`Plugin ${plg}${plugin.name}${er} does not provide a default export`);
|
|
635
|
+
return Promise.reject(new Error(`Plugin ${plg}${plugin.name}${er} does not provide a default export`));
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
catch (err) {
|
|
639
|
+
this.log.error(`Failed to load plugin ${plg}${plugin.name}${er}: ${err}`);
|
|
640
|
+
return Promise.reject(new Error(`Failed to load plugin ${plg}${plugin.name}${er}: ${err}`));
|
|
641
|
+
}
|
|
642
|
+
}
|
|
516
643
|
/**
|
|
517
644
|
* Starts the Matterbridge based on the bridge mode.
|
|
518
645
|
* If the bridge mode is 'bridge', it creates a commissioning server, matter aggregator,
|
|
@@ -527,7 +654,7 @@ export class Matterbridge {
|
|
|
527
654
|
this.createMatterServer(this.storageManager);
|
|
528
655
|
if (this.bridgeMode === 'bridge') {
|
|
529
656
|
// Plugins are loaded by loadPlugin on startup and plugin.loaded is set to true
|
|
530
|
-
// Plugins are started by callback when Matterbridge is commissioned and plugin.started is set to true
|
|
657
|
+
// Plugins are started and configured by callback when Matterbridge is commissioned and plugin.started is set to true
|
|
531
658
|
this.log.debug(`Creating commissioning server context for ${plg}Matterbridge${db}`);
|
|
532
659
|
this.matterbridgeContext = this.createCommissioningServerContext('Matterbridge', 'Matterbridge', DeviceTypes.AGGREGATOR.code, 0xfff1, 'Matterbridge', 0x8000, 'Matterbridge aggregator');
|
|
533
660
|
this.log.debug(`Creating commissioning server for ${plg}Matterbridge${db}`);
|
|
@@ -540,10 +667,6 @@ export class Matterbridge {
|
|
|
540
667
|
await this.matterServer.addCommissioningServer(this.commissioningServer, { uniqueStorageKey: 'Matterbridge' });
|
|
541
668
|
this.log.debug('Starting matter server');
|
|
542
669
|
await this.startMatterServer();
|
|
543
|
-
this.registeredPlugins.forEach(async (plugin) => {
|
|
544
|
-
if (plugin.platform)
|
|
545
|
-
await plugin.platform.onMatterStarted();
|
|
546
|
-
});
|
|
547
670
|
this.showCommissioningQRCode(this.commissioningServer, this.matterbridgeContext, 'Matterbridge');
|
|
548
671
|
}
|
|
549
672
|
if (this.bridgeMode === 'childbridge') {
|
|
@@ -554,26 +677,13 @@ export class Matterbridge {
|
|
|
554
677
|
this.registeredPlugins.forEach(async (plugin) => {
|
|
555
678
|
if (!plugin.enabled)
|
|
556
679
|
return;
|
|
557
|
-
// Start the interval to check if the plugin is loaded
|
|
558
|
-
const loadedInterval = setInterval(async () => {
|
|
559
|
-
this.log.debug(`Waiting in load interval for plugin ${plg}${plugin.name}${db} to load (${plugin.loaded}) and start (${plugin.started}) and send devices ...`);
|
|
560
|
-
if (!plugin.loaded)
|
|
561
|
-
return;
|
|
562
|
-
plugin.started = true;
|
|
563
|
-
plugin.registeredDevices = 0;
|
|
564
|
-
clearInterval(loadedInterval);
|
|
565
|
-
}, 1000);
|
|
566
680
|
// Start the interval to check if the plugins is started
|
|
567
|
-
const
|
|
568
|
-
this.log.debug(`Waiting in
|
|
569
|
-
if (!plugin.
|
|
681
|
+
const startInterval = setInterval(async () => {
|
|
682
|
+
this.log.debug(`Waiting in start interval for plugin ${plg}${plugin.name}${db} to load (${plugin.loaded}) and start (${plugin.started}) and send devices ...`);
|
|
683
|
+
if (!plugin.loaded)
|
|
570
684
|
return;
|
|
571
685
|
if (plugin.type === 'AccessoryPlatform') {
|
|
572
|
-
this.
|
|
573
|
-
if (plugin.platform)
|
|
574
|
-
await plugin.platform.onStart('Matterbridge Accessory platform has started commissioning');
|
|
575
|
-
else
|
|
576
|
-
this.log.error(`Platform not found for plugin ${plg}${plugin.name}${er}`);
|
|
686
|
+
await this.startPlugin(plugin, 'Matterbridge Accessory platform has started');
|
|
577
687
|
this.registeredDevices.forEach(async (registeredDevice) => {
|
|
578
688
|
if (registeredDevice.plugin === plugin.name) {
|
|
579
689
|
plugin.storageContext = this.importCommissioningServerContext(plugin.name, registeredDevice.device); // Generate serialNumber and uniqueId
|
|
@@ -595,17 +705,13 @@ export class Matterbridge {
|
|
|
595
705
|
plugin.commissioningServer = this.createCommisioningServer(plugin.storageContext, plugin.name);
|
|
596
706
|
this.log.debug(`Creating aggregator for plugin ${plg}${plugin.name}${db}`);
|
|
597
707
|
plugin.aggregator = this.createMatterAggregator(plugin.storageContext); // Generate serialNumber and uniqueId
|
|
598
|
-
this.
|
|
599
|
-
if (plugin.platform)
|
|
600
|
-
await plugin.platform.onStart('Matterbridge Dynamic platform has started commissioning');
|
|
601
|
-
else
|
|
602
|
-
this.log.error(`Platform not found for plugin ${plg}${plugin.name}${er}`);
|
|
708
|
+
await this.startPlugin(plugin, 'Matterbridge Dynamic platform has started');
|
|
603
709
|
this.log.debug(`Adding matter aggregator to commissioning server for plugin ${plg}${plugin.name}${db}`);
|
|
604
710
|
plugin.commissioningServer.addDevice(plugin.aggregator);
|
|
605
711
|
this.log.debug(`Adding commissioning server to matter server for plugin ${plg}${plugin.name}${db}`);
|
|
606
712
|
await this.matterServer.addCommissioningServer(plugin.commissioningServer, { uniqueStorageKey: plugin.name });
|
|
607
713
|
}
|
|
608
|
-
clearInterval(
|
|
714
|
+
clearInterval(startInterval);
|
|
609
715
|
}, 1000);
|
|
610
716
|
});
|
|
611
717
|
// Start the interval to check if all plugins are loaded and started and so start the matter server
|
|
@@ -635,20 +741,18 @@ export class Matterbridge {
|
|
|
635
741
|
}
|
|
636
742
|
});
|
|
637
743
|
});
|
|
638
|
-
this.log.debug('Starting matter server');
|
|
639
744
|
await this.startMatterServer();
|
|
640
|
-
this.registeredPlugins
|
|
641
|
-
if (plugin.platform)
|
|
642
|
-
await plugin.platform.onMatterStarted();
|
|
745
|
+
for (const plugin of this.registeredPlugins) {
|
|
643
746
|
this.showCommissioningQRCode(plugin.commissioningServer, plugin.storageContext, plugin.name);
|
|
644
|
-
}
|
|
645
|
-
Logger.defaultLogLevel = Level.DEBUG;
|
|
747
|
+
}
|
|
748
|
+
Logger.defaultLogLevel = this.debugEnabled ? Level.DEBUG : Level.INFO;
|
|
646
749
|
clearInterval(startMatterInterval);
|
|
647
750
|
}, 1000);
|
|
648
751
|
return;
|
|
649
752
|
}
|
|
650
753
|
}
|
|
651
754
|
async startMatterServer() {
|
|
755
|
+
this.log.debug('Starting matter server');
|
|
652
756
|
await this.matterServer.start();
|
|
653
757
|
this.log.debug('Started matter server');
|
|
654
758
|
}
|
|
@@ -794,14 +898,18 @@ export class Matterbridge {
|
|
|
794
898
|
},
|
|
795
899
|
activeSessionsChangedCallback: (fabricIndex) => {
|
|
796
900
|
const info = commissioningServer.getActiveSessionInformation(fabricIndex);
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
this.log.
|
|
901
|
+
let connected = false;
|
|
902
|
+
info.forEach((session) => {
|
|
903
|
+
this.log.debug(`***Active session changed on fabric ${fabricIndex} ${session.fabric?.rootVendorId}/${session.fabric?.label} for ${plg}${name}${nf}`, debugStringify(session));
|
|
904
|
+
if (session.isPeerActive === true && session.secure === true && session.numberOfActiveSubscriptions >= 1) {
|
|
905
|
+
this.log.info(`***Controller ${session.fabric?.rootVendorId}/${session.fabric?.label} connected to ${plg}${name}${nf}`);
|
|
906
|
+
connected = true;
|
|
907
|
+
}
|
|
908
|
+
});
|
|
909
|
+
if (connected) {
|
|
800
910
|
if (this.bridgeMode === 'childbridge') {
|
|
801
911
|
const plugin = this.findPlugin(name);
|
|
802
912
|
if (plugin) {
|
|
803
|
-
if (plugin.connected === true)
|
|
804
|
-
return; // Only once cause the devices are already added to the plugins aggregator
|
|
805
913
|
plugin.paired = true;
|
|
806
914
|
plugin.connected = true;
|
|
807
915
|
}
|
|
@@ -809,45 +917,40 @@ export class Matterbridge {
|
|
|
809
917
|
setTimeout(() => {
|
|
810
918
|
if (this.bridgeMode === 'bridge') {
|
|
811
919
|
//Logger.defaultLogLevel = Level.INFO;
|
|
812
|
-
this.registeredPlugins
|
|
920
|
+
for (const plugin of this.registeredPlugins) {
|
|
813
921
|
if (!plugin.enabled)
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
this.log.info(`***Started plugin ${plg}${plugin.name}${nf}`);
|
|
820
|
-
}
|
|
821
|
-
else {
|
|
822
|
-
this.log.error(`***Platform not found for plugin ${plg}${plugin.name}${er}`);
|
|
823
|
-
}
|
|
824
|
-
});
|
|
825
|
-
Logger.defaultLogLevel = Level.DEBUG;
|
|
922
|
+
continue;
|
|
923
|
+
this.startPlugin(plugin, 'Matterbridge is commissioned and controllers are connected', true); // No await do it asyncronously
|
|
924
|
+
//this.configurePlugin(plugin); // No await do it asyncronously
|
|
925
|
+
}
|
|
926
|
+
Logger.defaultLogLevel = this.debugEnabled ? Level.DEBUG : Level.INFO;
|
|
826
927
|
}
|
|
827
928
|
if (this.bridgeMode === 'childbridge') {
|
|
828
929
|
//Logger.defaultLogLevel = Level.INFO;
|
|
829
930
|
const plugin = this.findPlugin(name);
|
|
830
|
-
if (
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
931
|
+
if (plugin && plugin.type === 'DynamicPlatform') {
|
|
932
|
+
for (const registeredDevice of this.registeredDevices) {
|
|
933
|
+
if (registeredDevice.plugin === name) {
|
|
934
|
+
this.log.info(`Adding bridged device ${dev}${registeredDevice.device.name}${nf} to aggregator for plugin ${plg}${plugin.name}${db}`);
|
|
935
|
+
if (!plugin.aggregator) {
|
|
936
|
+
this.log.error(`****Aggregator not found for plugin ${plg}${plugin.name}${er}`);
|
|
937
|
+
continue;
|
|
938
|
+
}
|
|
939
|
+
plugin.aggregator.addBridgedDevice(registeredDevice.device);
|
|
940
|
+
if (plugin.addedDevices !== undefined)
|
|
941
|
+
plugin.addedDevices++;
|
|
942
|
+
this.log.info(`Added bridged device(${plugin.registeredDevices}/${plugin.addedDevices}) ${dev}${registeredDevice.device.name}${nf} for plugin ${plg}${plugin.name}${nf}`);
|
|
943
|
+
registeredDevice.added = true;
|
|
944
|
+
}
|
|
839
945
|
}
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
946
|
+
}
|
|
947
|
+
for (const plugin of this.registeredPlugins) {
|
|
948
|
+
if (plugin.name === name && plugin.platform) {
|
|
949
|
+
this.configurePlugin(plugin); // No await do it asyncronously
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
Logger.defaultLogLevel = this.debugEnabled ? Level.DEBUG : Level.INFO;
|
|
846
953
|
}
|
|
847
|
-
this.registeredPlugins.forEach(async (plugin) => {
|
|
848
|
-
if (plugin.name === name && plugin.platform)
|
|
849
|
-
plugin.platform.onConfigure();
|
|
850
|
-
});
|
|
851
954
|
//logEndpoint(commissioningServer.getRootEndpoint());
|
|
852
955
|
}, 2000);
|
|
853
956
|
}
|
|
@@ -987,6 +1090,10 @@ export class Matterbridge {
|
|
|
987
1090
|
await fs.mkdir(this.matterbridgeDirectory);
|
|
988
1091
|
}
|
|
989
1092
|
this.log.debug(`Matterbridge Directory: ${this.matterbridgeDirectory}`);
|
|
1093
|
+
// Matterbridge version
|
|
1094
|
+
const packageJson = JSON.parse(await fs.readFile(path.join(this.rootDirectory, 'package.json'), 'utf-8'));
|
|
1095
|
+
this.matterbridgeVersion = packageJson.version;
|
|
1096
|
+
this.log.debug(`Matterbridge Version: ${this.matterbridgeVersion}`);
|
|
990
1097
|
// Current working directory
|
|
991
1098
|
const currentDir = process.cwd();
|
|
992
1099
|
this.log.debug(`Current Working Directory: ${currentDir}`);
|
|
@@ -994,7 +1101,24 @@ export class Matterbridge {
|
|
|
994
1101
|
const cmdArgs = process.argv.slice(2).join(' ');
|
|
995
1102
|
this.log.debug(`Command Line Arguments: ${cmdArgs}`);
|
|
996
1103
|
}
|
|
997
|
-
|
|
1104
|
+
getBaseRegisteredPlugins() {
|
|
1105
|
+
const baseRegisteredPlugins = this.registeredPlugins.map((plugin) => ({
|
|
1106
|
+
path: plugin.path,
|
|
1107
|
+
type: plugin.type,
|
|
1108
|
+
name: plugin.name,
|
|
1109
|
+
version: plugin.version,
|
|
1110
|
+
description: plugin.description,
|
|
1111
|
+
author: plugin.author,
|
|
1112
|
+
enabled: plugin.enabled,
|
|
1113
|
+
loaded: plugin.loaded,
|
|
1114
|
+
started: plugin.started,
|
|
1115
|
+
paired: plugin.paired,
|
|
1116
|
+
connected: plugin.connected,
|
|
1117
|
+
registeredDevices: plugin.registeredDevices,
|
|
1118
|
+
}));
|
|
1119
|
+
return baseRegisteredPlugins;
|
|
1120
|
+
}
|
|
1121
|
+
getBaseRegisteredDevices() {
|
|
998
1122
|
const baseRegisteredPlugins = this.registeredPlugins.map((plugin) => ({
|
|
999
1123
|
path: plugin.path,
|
|
1000
1124
|
type: plugin.type,
|
|
@@ -1044,8 +1168,7 @@ export class Matterbridge {
|
|
|
1044
1168
|
// Endpoint to provide plugins
|
|
1045
1169
|
this.app.get('/api/plugins', (req, res) => {
|
|
1046
1170
|
this.log.debug('The frontend sent /api/plugins');
|
|
1047
|
-
|
|
1048
|
-
res.json(baseRegisteredPlugins);
|
|
1171
|
+
res.json(this.getBaseRegisteredPlugins());
|
|
1049
1172
|
});
|
|
1050
1173
|
// Endpoint to provide devices
|
|
1051
1174
|
this.app.get('/api/devices', (req, res) => {
|
|
@@ -1077,15 +1200,15 @@ export class Matterbridge {
|
|
|
1077
1200
|
// Endpoint to provide the cluster servers of the devices
|
|
1078
1201
|
this.app.get('/api/devices_clusters/:selectedPluginName/:selectedDeviceEndpoint', (req, res) => {
|
|
1079
1202
|
const selectedPluginName = req.params.selectedPluginName;
|
|
1080
|
-
const selectedDeviceEndpoint = req.params.selectedDeviceEndpoint;
|
|
1203
|
+
const selectedDeviceEndpoint = parseInt(req.params.selectedDeviceEndpoint, 10);
|
|
1081
1204
|
this.log.debug(`The frontend sent /api/devices_clusters plugin:${selectedPluginName} endpoint:${selectedDeviceEndpoint}`);
|
|
1082
|
-
if (selectedPluginName === 'none'
|
|
1205
|
+
if (selectedPluginName === 'none') {
|
|
1083
1206
|
res.json([]);
|
|
1084
1207
|
return;
|
|
1085
1208
|
}
|
|
1086
1209
|
const data = [];
|
|
1087
1210
|
this.registeredDevices.forEach((registeredDevice) => {
|
|
1088
|
-
if (registeredDevice.plugin === selectedPluginName) {
|
|
1211
|
+
if (registeredDevice.plugin === selectedPluginName && registeredDevice.device.id === selectedDeviceEndpoint) {
|
|
1089
1212
|
const clusterServers = registeredDevice.device.getAllClusterServers();
|
|
1090
1213
|
clusterServers.forEach((clusterServer) => {
|
|
1091
1214
|
Object.entries(clusterServer.attributes).forEach(([key, value]) => {
|
|
@@ -1189,6 +1312,13 @@ ws.onmessage = (event) => {
|
|
|
1189
1312
|
console.log(`Received message => ${event.data}`);
|
|
1190
1313
|
};
|
|
1191
1314
|
|
|
1315
|
+
*/
|
|
1316
|
+
/*
|
|
1317
|
+
// In Matterbridge
|
|
1318
|
+
global.matterbridgeInstance = Matterbridge.loadInstance();
|
|
1319
|
+
|
|
1320
|
+
// In plugins
|
|
1321
|
+
const matterbridge = global.matterbridgeInstance;
|
|
1192
1322
|
*/
|
|
1193
1323
|
/*
|
|
1194
1324
|
npx create-react-app matterbridge-frontend
|