matterbridge 3.4.0-dev-20251120-1b65c89 → 3.4.0-dev-20251120-5724e43
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 +7 -1
- package/README-DEV.md +6 -0
- package/dist/frontend.js +1 -0
- package/dist/matterbridge.js +7 -2
- package/dist/matterbridgePlatform.js +87 -48
- package/dist/pluginManager.js +10 -2
- package/dist/utils/spawn.js +6 -1
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -34,7 +34,7 @@ Advantages:
|
|
|
34
34
|
|
|
35
35
|
Removed the following long deprecated elements:
|
|
36
36
|
|
|
37
|
-
- [platform]: Matterbridge instead of PlatformMatterbridge in the platform constructor (deprecated since 3.
|
|
37
|
+
- [platform]: Matterbridge instead of PlatformMatterbridge in the platform constructor (deprecated since 3.3.0).
|
|
38
38
|
- [endpoint]: uniqueStorageKey instead of id in MatterbridgeEndpointOptions (deprecated since months).
|
|
39
39
|
- [endpoint]: endpointId instead of number in MatterbridgeEndpointOptions (deprecated since months).
|
|
40
40
|
|
|
@@ -43,11 +43,17 @@ Removed the following long deprecated elements:
|
|
|
43
43
|
- [endpoint]: Added getChildEndpointById() and getChildEndpointByOriginalId().
|
|
44
44
|
- [endpoint]: Deprecated getChildEndpointByName(). Use getChildEndpointById() or getChildEndpointByOriginalId().
|
|
45
45
|
- [platform]: Added wssSendSnackbarMessage method to MatterbridgePlatform for sending snackbar notifications to the frontend.
|
|
46
|
+
- [doorLock]: Added autoRelockTime attribute with default 0.
|
|
47
|
+
- [DevContainer]: Added instructions for testing a plugin with a paired controller when using DevContainer.
|
|
48
|
+
- [platform]: Made internal use methods and properties hard-private.
|
|
49
|
+
- [platform]: Added size(), getDeviceByName(), getDeviceByUniqueId(), getDeviceBySerialNumber(), getDeviceById(), getDeviceByOriginalId(), getDeviceByNumber() and hasDeviceUniqueId().
|
|
50
|
+
- [platform]: Added isReady, isLoaded, isStarted and isConfigured.
|
|
46
51
|
|
|
47
52
|
### Changed
|
|
48
53
|
|
|
49
54
|
- [package]: Updated dependencies.
|
|
50
55
|
- [deviceManager]: Bumped DeviceManager v.1.1.1.
|
|
56
|
+
- [pluginManager]: Bumped PluginManager v.1.3.1.
|
|
51
57
|
- [broadcastServer]: Bumped BroadcastServer v.1.0.3.
|
|
52
58
|
- [jest]: Bumped jestHelpers v.1.0.13.
|
|
53
59
|
- [spawn]: Bumped spawn module v.1.2.0.
|
package/README-DEV.md
CHANGED
|
@@ -54,6 +54,12 @@ To start the Dev Container, simply open the project folder in [Visual Studio Cod
|
|
|
54
54
|
|
|
55
55
|
Since Dev Container doesn't run in network mode 'host', it is not possible to pair Mattebridge running inside the Dev Container.
|
|
56
56
|
|
|
57
|
+
When you want to test your plugin with a paired controller, you have several options:
|
|
58
|
+
|
|
59
|
+
- create a tgz (npm run npmPack) and upload it to a running instance of matterbridge.
|
|
60
|
+
- publish it with tag dev and install it (matterbridge-yourplugin@dev in Install plugins) in a running instance of matterbridge.
|
|
61
|
+
- use a local instance of matterbridge running outside the dev container and install (../matterbridge-yourplugin in Install plugins) or add (../matterbridge-yourplugin in Install plugins) your plugin to it (easiest way). Adjust the path if matterbridge dir and your plugin dir are not in the same parent directory.
|
|
62
|
+
|
|
57
63
|
## Guidelines on imports/exports
|
|
58
64
|
|
|
59
65
|
Matterbridge exports from:
|
package/dist/frontend.js
CHANGED
|
@@ -1648,6 +1648,7 @@ export class Frontend extends EventEmitter {
|
|
|
1648
1648
|
else if (data.params.value === 'Fatal') {
|
|
1649
1649
|
Logger.level = MatterLogLevel.FATAL;
|
|
1650
1650
|
}
|
|
1651
|
+
this.matterbridge.matterLogLevel = MatterLogLevel.names[Logger.level];
|
|
1651
1652
|
let callbackLogLevel = "notice";
|
|
1652
1653
|
if (this.matterbridge.getLogLevel() === "info" || Logger.level === MatterLogLevel.INFO)
|
|
1653
1654
|
callbackLogLevel = "info";
|
package/dist/matterbridge.js
CHANGED
|
@@ -66,8 +66,10 @@ export class Matterbridge extends EventEmitter {
|
|
|
66
66
|
virtualMode = 'outlet';
|
|
67
67
|
profile = getParameter('profile');
|
|
68
68
|
log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4, logLevel: hasParameter('debug') ? "debug" : "info" });
|
|
69
|
+
logLevel = this.log.logLevel;
|
|
69
70
|
fileLogger = false;
|
|
70
|
-
matterLog = new AnsiLogger({ logName: 'Matter', logTimestampFormat: 4, logLevel: "debug" });
|
|
71
|
+
matterLog = new AnsiLogger({ logName: 'Matter', logTimestampFormat: 4, logLevel: hasParameter('debug') ? "debug" : "info" });
|
|
72
|
+
matterLogLevel = this.matterLog.logLevel;
|
|
71
73
|
matterFileLogger = false;
|
|
72
74
|
readOnly = hasParameter('readonly') || hasParameter('shelly');
|
|
73
75
|
shellyBoard = hasParameter('shelly');
|
|
@@ -320,6 +322,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
320
322
|
else {
|
|
321
323
|
this.log.logLevel = await this.nodeContext.get('matterbridgeLogLevel', this.shellyBoard ? "notice" : "info");
|
|
322
324
|
}
|
|
325
|
+
this.logLevel = this.log.logLevel;
|
|
323
326
|
this.frontend.logLevel = this.log.logLevel;
|
|
324
327
|
MatterbridgeEndpoint.logLevel = this.log.logLevel;
|
|
325
328
|
if (hasParameter('filelogger') || (await this.nodeContext.get('matterbridgeFileLog', false))) {
|
|
@@ -359,11 +362,12 @@ export class Matterbridge extends EventEmitter {
|
|
|
359
362
|
Logger.level = (await this.nodeContext.get('matterLogLevel', this.shellyBoard ? MatterLogLevel.NOTICE : MatterLogLevel.INFO));
|
|
360
363
|
}
|
|
361
364
|
Logger.format = MatterLogFormat.ANSI;
|
|
365
|
+
this.matterLogLevel = MatterLogLevel.names[Logger.level];
|
|
362
366
|
if (hasParameter('matterfilelogger') || (await this.nodeContext.get('matterFileLog', false))) {
|
|
363
367
|
this.matterFileLogger = true;
|
|
364
368
|
}
|
|
365
369
|
Logger.destinations.default.write = this.createDestinationMatterLogger(this.matterFileLogger);
|
|
366
|
-
this.log.debug(`Matter logLevel: ${
|
|
370
|
+
this.log.debug(`Matter logLevel: ${this.matterLogLevel} fileLoger: ${this.matterFileLogger}.`);
|
|
367
371
|
const networkInterfaces = os.networkInterfaces();
|
|
368
372
|
const availableAddresses = Object.entries(networkInterfaces);
|
|
369
373
|
const availableInterfaceNames = Object.keys(networkInterfaces);
|
|
@@ -841,6 +845,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
841
845
|
this.log.debug(`Command Line Arguments: ${cmdArgs}`);
|
|
842
846
|
}
|
|
843
847
|
async setLogLevel(logLevel) {
|
|
848
|
+
this.logLevel = logLevel;
|
|
844
849
|
this.log.logLevel = logLevel;
|
|
845
850
|
this.frontend.logLevel = logLevel;
|
|
846
851
|
MatterbridgeEndpoint.logLevel = logLevel;
|
|
@@ -20,14 +20,17 @@ export class MatterbridgePlatform {
|
|
|
20
20
|
version = '1.0.0';
|
|
21
21
|
storage;
|
|
22
22
|
context;
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
23
|
+
isReady = false;
|
|
24
|
+
isLoaded = false;
|
|
25
|
+
isStarted = false;
|
|
26
|
+
isConfigured = false;
|
|
27
|
+
#selectDevices = new Map();
|
|
28
|
+
#selectEntities = new Map();
|
|
29
|
+
#contextReady;
|
|
30
|
+
#selectDeviceContextReady;
|
|
31
|
+
#selectEntityContextReady;
|
|
28
32
|
ready;
|
|
29
|
-
|
|
30
|
-
registeredEndpointsByName = new Map();
|
|
33
|
+
#registeredEndpoints = new Map();
|
|
31
34
|
#server;
|
|
32
35
|
#debug = hasParameter('debug') || hasParameter('verbose');
|
|
33
36
|
#verbose = hasParameter('verbose');
|
|
@@ -40,8 +43,10 @@ export class MatterbridgePlatform {
|
|
|
40
43
|
this.log.debug(`Creating MatterbridgePlatform for plugin ${this.config.name}`);
|
|
41
44
|
if (this.#verbose)
|
|
42
45
|
this.log.debug(`Creating MatterbridgePlatform for plugin ${this.config.name} with config:\n${JSON.stringify(this.config, null, 2)}\n`);
|
|
43
|
-
if (!isValidString(this.config.name, 1))
|
|
46
|
+
if (!isValidString(this.config.name, 1)) {
|
|
47
|
+
this.#server.close();
|
|
44
48
|
throw new Error('Platform: the plugin name is missing or invalid.');
|
|
49
|
+
}
|
|
45
50
|
this.log.debug(`Creating storage for plugin ${this.config.name} in ${path.join(this.matterbridge.matterbridgeDirectory, this.config.name)}`);
|
|
46
51
|
this.storage = new NodeStorageManager({
|
|
47
52
|
dir: path.join(this.matterbridge.matterbridgeDirectory, this.config.name),
|
|
@@ -51,32 +56,47 @@ export class MatterbridgePlatform {
|
|
|
51
56
|
forgiveParseErrors: true,
|
|
52
57
|
});
|
|
53
58
|
this.log.debug(`Creating context for plugin ${this.config.name}`);
|
|
54
|
-
this
|
|
59
|
+
this.#contextReady = this.storage.createStorage('context').then((context) => {
|
|
55
60
|
this.context = context;
|
|
56
61
|
this.log.debug(`Created context for plugin ${this.config.name}`);
|
|
57
62
|
return;
|
|
58
63
|
});
|
|
59
64
|
this.log.debug(`Loading selectDevice for plugin ${this.config.name}`);
|
|
60
|
-
this
|
|
65
|
+
this.#selectDeviceContextReady = this.storage.createStorage('selectDevice').then(async (context) => {
|
|
61
66
|
const selectDevice = await context.get('selectDevice', []);
|
|
62
67
|
for (const device of selectDevice)
|
|
63
|
-
this.
|
|
64
|
-
this.log.debug(`Loaded ${this.
|
|
68
|
+
this.#selectDevices.set(device.serial, device);
|
|
69
|
+
this.log.debug(`Loaded ${this.#selectDevices.size} selectDevice for plugin ${this.config.name}`);
|
|
65
70
|
return;
|
|
66
71
|
});
|
|
67
72
|
this.log.debug(`Loading selectEntity for plugin ${this.config.name}`);
|
|
68
|
-
this
|
|
73
|
+
this.#selectEntityContextReady = this.storage.createStorage('selectEntity').then(async (context) => {
|
|
69
74
|
const selectEntity = await context.get('selectEntity', []);
|
|
70
75
|
for (const entity of selectEntity)
|
|
71
|
-
this.
|
|
72
|
-
this.log.debug(`Loaded ${this.
|
|
76
|
+
this.#selectEntities.set(entity.name, entity);
|
|
77
|
+
this.log.debug(`Loaded ${this.#selectEntities.size} selectEntity for plugin ${this.config.name}`);
|
|
73
78
|
return;
|
|
74
79
|
});
|
|
75
|
-
this.ready = Promise.all([this
|
|
80
|
+
this.ready = Promise.all([this.#contextReady, this.#selectDeviceContextReady, this.#selectEntityContextReady]).then(() => {
|
|
76
81
|
this.log.debug(`MatterbridgePlatform for plugin ${this.config.name} is fully initialized`);
|
|
82
|
+
this.isReady = true;
|
|
77
83
|
return;
|
|
78
84
|
});
|
|
79
85
|
}
|
|
86
|
+
async destroy() {
|
|
87
|
+
if (this.#verbose)
|
|
88
|
+
this.log.debug(`Destroying MatterbridgePlatform for plugin ${this.config.name}`);
|
|
89
|
+
this.#selectDevices.clear();
|
|
90
|
+
this.#selectEntities.clear();
|
|
91
|
+
this.#registeredEndpoints.clear();
|
|
92
|
+
await this.context?.close();
|
|
93
|
+
this.context = undefined;
|
|
94
|
+
await this.storage?.close();
|
|
95
|
+
this.#server.close();
|
|
96
|
+
if (this.#verbose)
|
|
97
|
+
this.log.debug(`Destroyed MatterbridgePlatform for plugin ${this.config.name}`);
|
|
98
|
+
this.isReady = false;
|
|
99
|
+
}
|
|
80
100
|
async onStart(reason) {
|
|
81
101
|
this.log.error('Plugins must override onStart.', reason);
|
|
82
102
|
throw new Error('Plugins must override onStart.');
|
|
@@ -90,14 +110,7 @@ export class MatterbridgePlatform {
|
|
|
90
110
|
this.log.debug(`Shutting down platform ${this.name}`, reason);
|
|
91
111
|
await this.saveSelects();
|
|
92
112
|
await this.checkEndpointNumbers();
|
|
93
|
-
this.
|
|
94
|
-
this.selectEntity.clear();
|
|
95
|
-
this.registeredEndpointsByUniqueId.clear();
|
|
96
|
-
this.registeredEndpointsByName.clear();
|
|
97
|
-
await this.context?.close();
|
|
98
|
-
this.context = undefined;
|
|
99
|
-
await this.storage?.close();
|
|
100
|
-
this.#server.close();
|
|
113
|
+
await this.destroy();
|
|
101
114
|
}
|
|
102
115
|
async onChangeLoggerLevel(logLevel) {
|
|
103
116
|
this.log.debug(`The plugin doesn't override onChangeLoggerLevel. Logger level set to: ${logLevel}`);
|
|
@@ -135,11 +148,35 @@ export class MatterbridgePlatform {
|
|
|
135
148
|
wssSendSnackbarMessage(message, timeout, severity) {
|
|
136
149
|
this.#server.request({ type: 'frontend_snackbarmessage', src: 'platform', dst: 'frontend', params: { message, timeout, severity } });
|
|
137
150
|
}
|
|
151
|
+
size() {
|
|
152
|
+
return this.#registeredEndpoints.size;
|
|
153
|
+
}
|
|
138
154
|
getDevices() {
|
|
139
|
-
return Array.from(this.
|
|
155
|
+
return Array.from(this.#registeredEndpoints.values());
|
|
156
|
+
}
|
|
157
|
+
getDeviceByName(deviceName) {
|
|
158
|
+
return Array.from(this.#registeredEndpoints.values()).find((device) => device.deviceName === deviceName);
|
|
159
|
+
}
|
|
160
|
+
getDeviceByUniqueId(uniqueId) {
|
|
161
|
+
return Array.from(this.#registeredEndpoints.values()).find((device) => device.uniqueId === uniqueId);
|
|
162
|
+
}
|
|
163
|
+
getDeviceBySerialNumber(serialNumber) {
|
|
164
|
+
return Array.from(this.#registeredEndpoints.values()).find((device) => device.serialNumber === serialNumber);
|
|
165
|
+
}
|
|
166
|
+
getDeviceById(id) {
|
|
167
|
+
return Array.from(this.#registeredEndpoints.values()).find((device) => device.maybeId === id);
|
|
168
|
+
}
|
|
169
|
+
getDeviceByOriginalId(originalId) {
|
|
170
|
+
return Array.from(this.#registeredEndpoints.values()).find((device) => device.originalId === originalId);
|
|
171
|
+
}
|
|
172
|
+
getDeviceByNumber(number) {
|
|
173
|
+
return Array.from(this.#registeredEndpoints.values()).find((device) => device.maybeNumber === number);
|
|
140
174
|
}
|
|
141
175
|
hasDeviceName(deviceName) {
|
|
142
|
-
return this.
|
|
176
|
+
return Array.from(this.#registeredEndpoints.values()).find((device) => device.deviceName === deviceName) !== undefined;
|
|
177
|
+
}
|
|
178
|
+
hasDeviceUniqueId(deviceUniqueId) {
|
|
179
|
+
return this.#registeredEndpoints.has(deviceUniqueId);
|
|
143
180
|
}
|
|
144
181
|
async registerVirtualDevice(name, type, callback) {
|
|
145
182
|
let aggregator;
|
|
@@ -176,7 +213,7 @@ export class MatterbridgePlatform {
|
|
|
176
213
|
this.log.error(`Device with uniqueId ${CYAN}${device.uniqueId}${er} has no serialNumber. The device will not be added.`);
|
|
177
214
|
return;
|
|
178
215
|
}
|
|
179
|
-
if (this.
|
|
216
|
+
if (this.hasDeviceName(device.deviceName)) {
|
|
180
217
|
this.log.error(`Device with name ${CYAN}${device.deviceName}${er} is already registered. The device will not be added. Please change the device name.`);
|
|
181
218
|
return;
|
|
182
219
|
}
|
|
@@ -201,48 +238,44 @@ export class MatterbridgePlatform {
|
|
|
201
238
|
}
|
|
202
239
|
}
|
|
203
240
|
await this.matterbridge.addBridgedEndpoint(this.name, device);
|
|
204
|
-
this.
|
|
205
|
-
this.registeredEndpointsByName.set(device.deviceName, device);
|
|
241
|
+
this.#registeredEndpoints.set(device.uniqueId, device);
|
|
206
242
|
}
|
|
207
243
|
async unregisterDevice(device) {
|
|
208
244
|
await this.matterbridge.removeBridgedEndpoint(this.name, device);
|
|
209
245
|
if (device.uniqueId)
|
|
210
|
-
this.
|
|
211
|
-
if (device.deviceName)
|
|
212
|
-
this.registeredEndpointsByName.delete(device.deviceName);
|
|
246
|
+
this.#registeredEndpoints.delete(device.uniqueId);
|
|
213
247
|
}
|
|
214
248
|
async unregisterAllDevices(delay = 0) {
|
|
215
249
|
await this.matterbridge.removeAllBridgedEndpoints(this.name, delay);
|
|
216
|
-
this.
|
|
217
|
-
this.registeredEndpointsByName.clear();
|
|
250
|
+
this.#registeredEndpoints.clear();
|
|
218
251
|
}
|
|
219
252
|
async saveSelects() {
|
|
220
253
|
if (this.storage) {
|
|
221
|
-
this.log.debug(`Saving ${this.
|
|
254
|
+
this.log.debug(`Saving ${this.#selectDevices.size} selectDevice...`);
|
|
222
255
|
const selectDevice = await this.storage.createStorage('selectDevice');
|
|
223
|
-
await selectDevice.set('selectDevice', Array.from(this.
|
|
256
|
+
await selectDevice.set('selectDevice', Array.from(this.#selectDevices.values()));
|
|
224
257
|
await selectDevice.close();
|
|
225
|
-
this.log.debug(`Saving ${this.
|
|
258
|
+
this.log.debug(`Saving ${this.#selectEntities.size} selectEntity...`);
|
|
226
259
|
const selectEntity = await this.storage.createStorage('selectEntity');
|
|
227
|
-
await selectEntity.set('selectEntity', Array.from(this.
|
|
260
|
+
await selectEntity.set('selectEntity', Array.from(this.#selectEntities.values()));
|
|
228
261
|
await selectEntity.close();
|
|
229
262
|
}
|
|
230
263
|
}
|
|
231
264
|
async clearSelect() {
|
|
232
|
-
this.
|
|
233
|
-
this.
|
|
265
|
+
this.#selectDevices.clear();
|
|
266
|
+
this.#selectEntities.clear();
|
|
234
267
|
await this.saveSelects();
|
|
235
268
|
}
|
|
236
269
|
async clearDeviceSelect(serial) {
|
|
237
|
-
this.
|
|
270
|
+
this.#selectDevices.delete(serial);
|
|
238
271
|
await this.saveSelects();
|
|
239
272
|
}
|
|
240
273
|
async clearEntitySelect(name) {
|
|
241
|
-
this.
|
|
274
|
+
this.#selectEntities.delete(name);
|
|
242
275
|
await this.saveSelects();
|
|
243
276
|
}
|
|
244
277
|
setSelectDevice(serial, name, configUrl, icon, entities) {
|
|
245
|
-
const device = this.
|
|
278
|
+
const device = this.#selectDevices.get(serial);
|
|
246
279
|
if (device) {
|
|
247
280
|
device.serial = serial;
|
|
248
281
|
device.name = name;
|
|
@@ -254,11 +287,14 @@ export class MatterbridgePlatform {
|
|
|
254
287
|
device.entities = entities;
|
|
255
288
|
}
|
|
256
289
|
else {
|
|
257
|
-
this.
|
|
290
|
+
this.#selectDevices.set(serial, { serial, name, configUrl, icon, entities });
|
|
258
291
|
}
|
|
259
292
|
}
|
|
293
|
+
getSelectDevice(serial) {
|
|
294
|
+
return this.#selectDevices.get(serial);
|
|
295
|
+
}
|
|
260
296
|
setSelectDeviceEntity(serial, entityName, entityDescription, entityIcon) {
|
|
261
|
-
const device = this.
|
|
297
|
+
const device = this.#selectDevices.get(serial);
|
|
262
298
|
if (device) {
|
|
263
299
|
if (!device.entities)
|
|
264
300
|
device.entities = [];
|
|
@@ -268,17 +304,20 @@ export class MatterbridgePlatform {
|
|
|
268
304
|
}
|
|
269
305
|
getSelectDevices() {
|
|
270
306
|
const selectDevices = [];
|
|
271
|
-
for (const device of this.
|
|
307
|
+
for (const device of this.#selectDevices.values()) {
|
|
272
308
|
selectDevices.push({ pluginName: this.name, ...device });
|
|
273
309
|
}
|
|
274
310
|
return selectDevices;
|
|
275
311
|
}
|
|
276
312
|
setSelectEntity(name, description, icon) {
|
|
277
|
-
this.
|
|
313
|
+
this.#selectEntities.set(name, { name, description, icon });
|
|
314
|
+
}
|
|
315
|
+
getSelectEntity(name) {
|
|
316
|
+
return this.#selectEntities.get(name);
|
|
278
317
|
}
|
|
279
318
|
getSelectEntities() {
|
|
280
319
|
const selectEntities = [];
|
|
281
|
-
for (const entity of this.
|
|
320
|
+
for (const entity of this.#selectEntities.values()) {
|
|
282
321
|
selectEntities.push({ pluginName: this.name, ...entity });
|
|
283
322
|
}
|
|
284
323
|
return selectEntities;
|
package/dist/pluginManager.js
CHANGED
|
@@ -266,6 +266,7 @@ export class PluginManager extends EventEmitter {
|
|
|
266
266
|
const pluginsArray = await this.matterbridge.nodeContext.get('plugins', []);
|
|
267
267
|
for (const plugin of pluginsArray)
|
|
268
268
|
this._plugins.set(plugin.name, plugin);
|
|
269
|
+
this.log.debug(`Loaded ${BLUE}${pluginsArray.length}${db} plugins from storage`);
|
|
269
270
|
return pluginsArray;
|
|
270
271
|
}
|
|
271
272
|
async saveToStorage() {
|
|
@@ -727,7 +728,7 @@ export class PluginManager extends EventEmitter {
|
|
|
727
728
|
const { pathToFileURL } = await import('node:url');
|
|
728
729
|
const pluginUrl = pathToFileURL(pluginEntry);
|
|
729
730
|
this.log.debug(`Importing plugin ${plg}${plugin.name}${db} from ${pluginUrl.href}`);
|
|
730
|
-
const pluginInstance = await import(pluginUrl.href);
|
|
731
|
+
const pluginInstance = (await import(pluginUrl.href));
|
|
731
732
|
this.log.debug(`Imported plugin ${plg}${plugin.name}${db} from ${pluginUrl.href}`);
|
|
732
733
|
if (pluginInstance.default) {
|
|
733
734
|
const config = await this.loadConfig(plugin);
|
|
@@ -739,12 +740,13 @@ export class PluginManager extends EventEmitter {
|
|
|
739
740
|
plugin.schemaJson = await this.loadSchema(plugin);
|
|
740
741
|
config.name = packageJson.name;
|
|
741
742
|
config.version = packageJson.version;
|
|
742
|
-
const log = new AnsiLogger({ logName: plugin.description, logTimestampFormat: 4, logLevel: config.debug ? "debug" : this.matterbridge.
|
|
743
|
+
const log = new AnsiLogger({ logName: plugin.description, logTimestampFormat: 4, logLevel: config.debug ? "debug" : this.matterbridge.logLevel });
|
|
743
744
|
const platform = pluginInstance.default(this.matterbridge, log, config);
|
|
744
745
|
config.type = platform.type;
|
|
745
746
|
platform.name = packageJson.name;
|
|
746
747
|
platform.config = config;
|
|
747
748
|
platform.version = packageJson.version;
|
|
749
|
+
platform.isLoaded = true;
|
|
748
750
|
plugin.name = packageJson.name;
|
|
749
751
|
plugin.description = packageJson.description ?? 'No description';
|
|
750
752
|
plugin.version = packageJson.version;
|
|
@@ -803,6 +805,7 @@ export class PluginManager extends EventEmitter {
|
|
|
803
805
|
await plugin.platform.onStart(message);
|
|
804
806
|
this.log.notice(`Started plugin ${plg}${plugin.name}${nt} type ${typ}${plugin.type}${nt}`);
|
|
805
807
|
plugin.started = true;
|
|
808
|
+
plugin.platform.isStarted = true;
|
|
806
809
|
await this.saveConfigFromPlugin(plugin);
|
|
807
810
|
this.emit('started', plugin.name);
|
|
808
811
|
if (configure)
|
|
@@ -845,6 +848,7 @@ export class PluginManager extends EventEmitter {
|
|
|
845
848
|
await plugin.platform.onConfigure();
|
|
846
849
|
this.log.notice(`Configured plugin ${plg}${plugin.name}${nt} type ${typ}${plugin.type}${nt}`);
|
|
847
850
|
plugin.configured = true;
|
|
851
|
+
plugin.platform.isConfigured = true;
|
|
848
852
|
this.emit('configured', plugin.name);
|
|
849
853
|
return plugin;
|
|
850
854
|
}
|
|
@@ -884,6 +888,10 @@ export class PluginManager extends EventEmitter {
|
|
|
884
888
|
this.log.info(`Shutting down plugin ${plg}${plugin.name}${nf}: ${reason}...`);
|
|
885
889
|
try {
|
|
886
890
|
await plugin.platform.onShutdown(reason);
|
|
891
|
+
plugin.platform.isReady = false;
|
|
892
|
+
plugin.platform.isLoaded = false;
|
|
893
|
+
plugin.platform.isStarted = false;
|
|
894
|
+
plugin.platform.isConfigured = false;
|
|
887
895
|
plugin.locked = undefined;
|
|
888
896
|
plugin.error = undefined;
|
|
889
897
|
plugin.loaded = undefined;
|
package/dist/utils/spawn.js
CHANGED
|
@@ -8,7 +8,12 @@ export async function spawnCommand(command, args, packageCommand, packageName) {
|
|
|
8
8
|
const log = new AnsiLogger({ logName: 'Spawn', logTimestampFormat: 4, logLevel: debug ? "debug" : "info" });
|
|
9
9
|
const server = new BroadcastServer('spawn', log);
|
|
10
10
|
const sendLog = (name, message) => {
|
|
11
|
-
|
|
11
|
+
try {
|
|
12
|
+
server.request({ type: 'frontend_logmessage', src: 'spawn', dst: 'frontend', params: { level: 'spawn', time: log.now(), name, message } });
|
|
13
|
+
}
|
|
14
|
+
catch (err) {
|
|
15
|
+
log.debug(`Failed to send log message to frontend: ${err instanceof Error ? err.message : String(err)}`);
|
|
16
|
+
}
|
|
12
17
|
};
|
|
13
18
|
if (verbose)
|
|
14
19
|
log.debug(`Spawning command: ${command} with ${args.join(' ')} ${packageCommand} ${packageName}`);
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "matterbridge",
|
|
3
|
-
"version": "3.4.0-dev-20251120-
|
|
3
|
+
"version": "3.4.0-dev-20251120-5724e43",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "matterbridge",
|
|
9
|
-
"version": "3.4.0-dev-20251120-
|
|
9
|
+
"version": "3.4.0-dev-20251120-5724e43",
|
|
10
10
|
"license": "Apache-2.0",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@matter/main": "0.15.6",
|
package/package.json
CHANGED