@matterbridge/core 3.10.14-dev-20261010-607ee18 → 3.10.14-dev-20261013-e87a0c8
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/dist/backendExpress.js +14 -9
- package/dist/backendWsServer.d.ts +1 -5
- package/dist/backendWsServer.js +4 -35
- package/dist/behaviors/bindingServer.d.ts +1 -1
- package/dist/behaviors/booleanStateConfigurationServer.js +2 -1
- package/dist/behaviors/cameraAvSettingsUserLevelManagementServer.d.ts +1 -1
- package/dist/behaviors/cameraAvSettingsUserLevelManagementServer.js +2 -1
- package/dist/behaviors/cameraAvStreamManagementServer.d.ts +1 -2
- package/dist/behaviors/cameraAvStreamManagementServer.js +2 -1
- package/dist/behaviors/chimeServer.js +2 -1
- package/dist/behaviors/deviceEnergyManagementServer.js +2 -1
- package/dist/behaviors/fanControlServer.js +2 -1
- package/dist/behaviors/pumpConfigurationAndControlServer.js +2 -1
- package/dist/behaviors/smokeCoAlarmServer.js +2 -1
- package/dist/behaviors/temperatureAlarmServer.js +2 -1
- package/dist/behaviors/thermostatServer.js +2 -1
- package/dist/behaviors/valveConfigurationAndControlServer.js +2 -1
- package/dist/behaviors/webRtcTransportProviderServer.js +3 -1
- package/dist/chipTests.js +3 -2
- package/dist/cli.js +36 -4
- package/dist/cliEmitter.d.ts +0 -3
- package/dist/deviceManager.d.ts +0 -1
- package/dist/deviceManager.js +15 -47
- package/dist/devices/airConditioner.d.ts +1 -1
- package/dist/devices/audioDoorbell.d.ts +1 -1
- package/dist/devices/audioDoorbell.js +1 -1
- package/dist/devices/batteryStorage.d.ts +1 -1
- package/dist/devices/camera.d.ts +1 -2
- package/dist/devices/camera.js +1 -1
- package/dist/devices/closure.d.ts +2 -2
- package/dist/devices/closure.js +1 -1
- package/dist/devices/closurePanel.js +1 -1
- package/dist/devices/cooktop.d.ts +2 -1
- package/dist/devices/dishwasher.d.ts +2 -2
- package/dist/devices/dishwasher.js +2 -1
- package/dist/devices/electricalUtilityMeter.d.ts +1 -1
- package/dist/devices/electricalUtilityMeter.js +1 -1
- package/dist/devices/evse.d.ts +1 -1
- package/dist/devices/evse.js +2 -1
- package/dist/devices/extractorHood.d.ts +1 -1
- package/dist/devices/floodlightCamera.d.ts +1 -1
- package/dist/devices/floodlightCamera.js +1 -1
- package/dist/devices/heatPump.d.ts +1 -1
- package/dist/devices/intercom.d.ts +1 -1
- package/dist/devices/intercom.js +1 -1
- package/dist/devices/irrigationSystem.d.ts +1 -1
- package/dist/devices/laundryDryer.d.ts +2 -2
- package/dist/devices/laundryDryer.js +2 -1
- package/dist/devices/laundryWasher.d.ts +2 -2
- package/dist/devices/laundryWasher.js +2 -1
- package/dist/devices/microwaveOven.d.ts +2 -2
- package/dist/devices/microwaveOven.js +2 -1
- package/dist/devices/oven.d.ts +2 -1
- package/dist/devices/refrigerator.d.ts +2 -1
- package/dist/devices/roboticVacuumCleaner.d.ts +1 -1
- package/dist/devices/snapshotCamera.d.ts +1 -1
- package/dist/devices/snapshotCamera.js +1 -1
- package/dist/devices/solarPower.d.ts +1 -1
- package/dist/devices/temperatureControl.js +2 -1
- package/dist/devices/videoDoorbell.d.ts +1 -1
- package/dist/devices/videoDoorbell.js +1 -1
- package/dist/devices/waterHeater.d.ts +1 -1
- package/dist/frontend.d.ts +1 -8
- package/dist/frontend.js +23 -82
- package/dist/matterNode.d.ts +4 -2
- package/dist/matterNode.js +116 -67
- package/dist/matterNodeHelpers.d.ts +3 -1
- package/dist/matterNodeHelpers.js +48 -0
- package/dist/matterbridge.js +14 -24
- package/dist/matterbridgeDeviceTypes.d.ts +1 -1
- package/dist/matterbridgeEndpoint.js +43 -29
- package/dist/matterbridgePlatform.js +39 -3
- package/dist/pluginManager.js +10 -1
- package/dist/runners/threadBackend.js +20 -6
- package/dist/runners/threadRootNode.js +32 -12
- package/dist/runners/threadTracker.js +23 -6
- package/package.json +5 -5
package/dist/matterNode.js
CHANGED
|
@@ -10,11 +10,11 @@ import { BridgedDeviceBasicInformationServer } from '@matter/node/behaviors/brid
|
|
|
10
10
|
import { PowerSourceServer } from '@matter/node/behaviors/power-source';
|
|
11
11
|
import { AggregatorEndpoint } from '@matter/node/endpoints/aggregator';
|
|
12
12
|
import { MdnsService, PaseClient } from '@matter/protocol';
|
|
13
|
-
import { DeviceTypeId, EndpointNumber, VendorId } from '@matter/types';
|
|
14
13
|
import { PowerSource } from '@matter/types/clusters/power-source';
|
|
14
|
+
import { DeviceTypeId, EndpointNumber, VendorId } from '@matter/types/datatype';
|
|
15
15
|
import { BroadcastServer } from '@matterbridge/thread/server';
|
|
16
16
|
import { dev, MATTER_LOGGER_FILE, MATTER_STORAGE_DIR, MATTERBRIDGE_LOGGER_FILE, NODE_STORAGE_DIR, plg } from '@matterbridge/types';
|
|
17
|
-
import { getIntParameter, getParameter, hasParameter } from '@matterbridge/utils/cli';
|
|
17
|
+
import { getIntParameter, getParameter, hasAnyParameter, hasParameter } from '@matterbridge/utils/cli';
|
|
18
18
|
import { copyDirectory } from '@matterbridge/utils/copy-dir';
|
|
19
19
|
import { getErrorMessage, inspectError } from '@matterbridge/utils/error';
|
|
20
20
|
import { logModuleLoaded } from '@matterbridge/utils/loader';
|
|
@@ -22,10 +22,9 @@ import { isValidInteger, isValidString, parseVersionString } from '@matterbridge
|
|
|
22
22
|
import { fireAndForget, wait, withTimeout } from '@matterbridge/utils/wait';
|
|
23
23
|
import { AnsiLogger, BLUE, CYAN, db, debugStringify, er, nf, or, zb } from 'node-ansi-logger';
|
|
24
24
|
import { NodeStorageManager } from 'node-persist-manager';
|
|
25
|
-
import { toBaseDevice } from './deviceManager.js';
|
|
26
25
|
import { addVirtualDevice } from './helpers.js';
|
|
27
26
|
import { bridge } from './matterbridgeDeviceTypes.js';
|
|
28
|
-
import { deleteAdvertisingNode, getServerNodeData, setAdvertisingNode } from './matterNodeHelpers.js';
|
|
27
|
+
import { deleteAdvertisingNode, getServerNodeData, setAdvertisingNode, toBaseDevice } from './matterNodeHelpers.js';
|
|
29
28
|
import { PluginManager } from './pluginManager.js';
|
|
30
29
|
logModuleLoaded('MatterNode');
|
|
31
30
|
export class MatterNode extends EventEmitter {
|
|
@@ -59,14 +58,16 @@ export class MatterNode extends EventEmitter {
|
|
|
59
58
|
pluginManager;
|
|
60
59
|
dependantMatterNodes = new Map();
|
|
61
60
|
server;
|
|
62
|
-
debug =
|
|
63
|
-
verbose =
|
|
61
|
+
debug = hasAnyParameter('debug', 'verbose', 'debug-node', 'verbose-node');
|
|
62
|
+
verbose = hasAnyParameter('verbose', 'verbose-node');
|
|
64
63
|
constructor(matterbridge, pluginName, device) {
|
|
65
64
|
super();
|
|
66
65
|
this.matterbridge = matterbridge;
|
|
67
66
|
this.pluginName = pluginName;
|
|
68
67
|
this.device = device;
|
|
69
68
|
this.log.logNameColor = '\x1b[38;5;65m';
|
|
69
|
+
this.log.logLevel = matterbridge.logLevel;
|
|
70
|
+
this.matterLog.logLevel = matterbridge.matterLogLevel;
|
|
70
71
|
if (this.debug)
|
|
71
72
|
this.log.debug(`MatterNode ${this.pluginName ? 'for plugin ' + this.pluginName : 'bridge'} loading...`);
|
|
72
73
|
this.storeId = this.device?.deviceName ? this.device.deviceName.replace(/[ .]/g, '') : (this.pluginName ?? 'Matterbridge');
|
|
@@ -75,12 +76,20 @@ export class MatterNode extends EventEmitter {
|
|
|
75
76
|
this.discriminator = matterbridge.discriminator;
|
|
76
77
|
this.mdnsInterface = matterbridge.mdnsInterface;
|
|
77
78
|
this.server = new BroadcastServer('matter', this.log);
|
|
78
|
-
this.server.on('broadcast_message', this.msgHandler
|
|
79
|
+
this.server.on('broadcast_message', (msg) => fireAndForget(this.msgHandler(msg), this.log, 'Broadcast message handler'));
|
|
79
80
|
if (this.verbose)
|
|
80
81
|
this.log.debug(`BroadcastServer is ready`);
|
|
81
|
-
|
|
82
|
-
|
|
82
|
+
const injectMatterbridge = {
|
|
83
|
+
...this.matterbridge,
|
|
84
|
+
getPlatformMatterbridge: () => this.matterbridge,
|
|
85
|
+
addBridgedEndpoint: this.addBridgedEndpoint.bind(this),
|
|
86
|
+
removeBridgedEndpoint: this.removeBridgedEndpoint.bind(this),
|
|
87
|
+
removeAllBridgedEndpoints: this.removeAllBridgedEndpoints.bind(this),
|
|
88
|
+
addVirtualEndpoint: this.addVirtualEndpoint.bind(this),
|
|
89
|
+
};
|
|
90
|
+
this.pluginManager = new PluginManager(injectMatterbridge);
|
|
83
91
|
this.pluginManager.server.close();
|
|
92
|
+
this.pluginManager.logLevel = this.debug ? "debug" : "info";
|
|
84
93
|
if (this.verbose)
|
|
85
94
|
this.log.debug(`PluginManager is ready`);
|
|
86
95
|
this.environment.vars.set('log.level', MatterLogLevel.DEBUG);
|
|
@@ -88,6 +97,7 @@ export class MatterNode extends EventEmitter {
|
|
|
88
97
|
this.environment.vars.set('path.root', path.join(matterbridge.matterbridgeDirectory, MATTER_STORAGE_DIR));
|
|
89
98
|
this.environment.vars.set('runtime.signals', false);
|
|
90
99
|
this.environment.vars.set('runtime.exitcode', false);
|
|
100
|
+
this.environment.vars.set('endpoint.validation', 'strict');
|
|
91
101
|
if (this.mdnsInterface)
|
|
92
102
|
this.environment.vars.set('mdns.networkInterface', this.mdnsInterface);
|
|
93
103
|
if (this.verbose)
|
|
@@ -106,10 +116,10 @@ export class MatterNode extends EventEmitter {
|
|
|
106
116
|
if (this.verbose)
|
|
107
117
|
this.log.debug(`Matter logLevel: ${levels[Logger.level]} fileLogger: ${matterbridge.matterFileLogger}.`);
|
|
108
118
|
if (this.debug)
|
|
109
|
-
this.log.debug(`MatterNode ${this.
|
|
119
|
+
this.log.debug(`MatterNode for ${this.storeId} loaded`);
|
|
110
120
|
}
|
|
111
121
|
async msgHandler(msg) {
|
|
112
|
-
if (this.server.isWorkerRequest(msg)
|
|
122
|
+
if (this.server.isWorkerRequest(msg)) {
|
|
113
123
|
if (this.verbose)
|
|
114
124
|
this.log.debug(`Received broadcast request ${CYAN}${msg.type}${db} from ${CYAN}${msg.src}${db}: ${debugStringify(msg)}${db}`);
|
|
115
125
|
switch (msg.type) {
|
|
@@ -159,6 +169,8 @@ export class MatterNode extends EventEmitter {
|
|
|
159
169
|
switch (msg.type) {
|
|
160
170
|
case 'get_log_level':
|
|
161
171
|
case 'set_log_level':
|
|
172
|
+
case 'matterbridge_platform':
|
|
173
|
+
case 'matterbridge_shared':
|
|
162
174
|
break;
|
|
163
175
|
default:
|
|
164
176
|
if (this.verbose)
|
|
@@ -183,11 +195,12 @@ export class MatterNode extends EventEmitter {
|
|
|
183
195
|
this.log.debug(`Destroyed MatterNode instance for ${this.storeId}`);
|
|
184
196
|
}
|
|
185
197
|
async create() {
|
|
186
|
-
this.log.info(
|
|
198
|
+
this.log.info(`Creating Matter node for ${this.storeId}...`);
|
|
187
199
|
const { result } = await this.server.fetch({ type: 'matterbridge_matterdata', src: this.server.name, dst: 'matterbridge' });
|
|
188
200
|
this.port = result.port;
|
|
189
201
|
this.passcode = result.passcode;
|
|
190
202
|
this.discriminator = result.discriminator;
|
|
203
|
+
this.log.debug(`Loaded Matter node parameters for ${this.storeId}: port ${CYAN}${this.port}${db} passcode ${CYAN}${this.passcode}${db} discriminator ${CYAN}${this.discriminator}${db}`);
|
|
191
204
|
await this.startMatterStorage();
|
|
192
205
|
this.pluginManager.matterbridge.nodeStorage = new NodeStorageManager({
|
|
193
206
|
dir: path.join(this.matterbridge.matterbridgeDirectory, NODE_STORAGE_DIR),
|
|
@@ -204,7 +217,16 @@ export class MatterNode extends EventEmitter {
|
|
|
204
217
|
this.emit('ready', this.device.deviceName.replace(/[ .]/g, ''));
|
|
205
218
|
return;
|
|
206
219
|
}
|
|
207
|
-
if (
|
|
220
|
+
if (this.pluginName) {
|
|
221
|
+
this.log.debug(`Creating MatterNode instance for plugin ${CYAN}${this.pluginName}${db}...`);
|
|
222
|
+
this.log.debug(`Loading plugin ${CYAN}${this.pluginName}${db}...`);
|
|
223
|
+
await this.pluginManager.load(this.pluginName);
|
|
224
|
+
this.pluginStatusUpdate(this.pluginName, { loaded: this.pluginManager.get(this.pluginName)?.loaded });
|
|
225
|
+
this.log.debug(`Loaded plugin ${CYAN}${this.pluginName}${db}`);
|
|
226
|
+
this.log.debug(`Created MatterNode instance for plugin ${CYAN}${this.pluginName}${db}`);
|
|
227
|
+
this.emit('ready', this.pluginName);
|
|
228
|
+
}
|
|
229
|
+
else {
|
|
208
230
|
this.log.debug('Creating MatterNode instance for all plugins...');
|
|
209
231
|
await this.createMatterbridgeServerNode();
|
|
210
232
|
this.log.debug('Loading all plugins...');
|
|
@@ -213,25 +235,20 @@ export class MatterNode extends EventEmitter {
|
|
|
213
235
|
loadPromises.push(this.pluginManager.load(plugin));
|
|
214
236
|
}
|
|
215
237
|
await Promise.all(loadPromises);
|
|
238
|
+
for (const plugin of this.pluginManager.array().filter((p) => p.enabled)) {
|
|
239
|
+
this.pluginStatusUpdate(plugin.name, { loaded: plugin.loaded });
|
|
240
|
+
}
|
|
216
241
|
this.log.debug('Loaded all plugins');
|
|
217
242
|
this.log.debug('Created MatterNode instance for all plugins');
|
|
218
243
|
this.emit('ready', 'Matterbridge');
|
|
219
244
|
}
|
|
220
|
-
|
|
221
|
-
this.log.debug(`Creating MatterNode instance for plugin ${CYAN}${this.pluginName}${db}...`);
|
|
222
|
-
this.log.debug(`Loading plugin ${CYAN}${this.pluginName}${db}...`);
|
|
223
|
-
await this.pluginManager.load(this.pluginName);
|
|
224
|
-
this.log.debug(`Loaded plugin ${CYAN}${this.pluginName}${db}`);
|
|
225
|
-
this.log.debug(`Created MatterNode instance for plugin ${CYAN}${this.pluginName}${db}`);
|
|
226
|
-
this.emit('ready', this.pluginName);
|
|
227
|
-
}
|
|
228
|
-
this.log.info('Created Matter node');
|
|
245
|
+
this.log.info(`Created Matter node for ${this.storeId}`);
|
|
229
246
|
await this.yieldToNode();
|
|
230
247
|
}
|
|
231
248
|
async start() {
|
|
232
249
|
if (!this.serverNode && !this.pluginName)
|
|
233
|
-
throw new Error(
|
|
234
|
-
this.log.info(
|
|
250
|
+
throw new Error(`Matter server node for ${this.storeId} not created yet. Call create() first.`);
|
|
251
|
+
this.log.info(`Starting MatterNode for ${this.storeId}...`);
|
|
235
252
|
if (this.pluginName && this.device?.deviceName) {
|
|
236
253
|
this.log.debug(`Starting MatterNode for server device ${this.pluginName}:${this.device.deviceName}...`);
|
|
237
254
|
await this.startServerNode();
|
|
@@ -239,43 +256,56 @@ export class MatterNode extends EventEmitter {
|
|
|
239
256
|
return;
|
|
240
257
|
}
|
|
241
258
|
if (!this.pluginName) {
|
|
242
|
-
this.log.debug(
|
|
259
|
+
this.log.debug(`Starting all plugins for ${this.storeId}...`);
|
|
243
260
|
const startPromises = [];
|
|
244
261
|
for (const plugin of this.pluginManager.array().filter((p) => p.enabled && p.loaded)) {
|
|
245
262
|
startPromises.push(this.pluginManager.start(plugin, 'Starting MatterNode'));
|
|
246
263
|
}
|
|
247
264
|
await Promise.all(startPromises);
|
|
248
|
-
this.
|
|
249
|
-
|
|
265
|
+
for (const plugin of this.pluginManager.array().filter((p) => p.enabled)) {
|
|
266
|
+
this.pluginStatusUpdate(plugin.name, { started: plugin.started, registeredDevices: plugin.registeredDevices });
|
|
267
|
+
}
|
|
268
|
+
this.log.debug(`Started all plugins for ${this.storeId}`);
|
|
269
|
+
this.log.debug(`Starting MatterNode for ${this.storeId}...`);
|
|
250
270
|
await this.startServerNode();
|
|
251
|
-
this.log.debug(
|
|
252
|
-
this.log.debug(
|
|
271
|
+
this.log.debug(`Started MatterNode for ${this.storeId}`);
|
|
272
|
+
this.log.debug(`Configuring all plugins for ${this.storeId}...`);
|
|
253
273
|
const configurePromises = [];
|
|
254
274
|
for (const plugin of this.pluginManager.array().filter((p) => p.enabled && p.started)) {
|
|
255
275
|
configurePromises.push(this.pluginManager.configure(plugin));
|
|
256
276
|
}
|
|
257
277
|
await Promise.all(configurePromises);
|
|
258
|
-
this.
|
|
278
|
+
for (const plugin of this.pluginManager.array().filter((p) => p.enabled)) {
|
|
279
|
+
this.pluginStatusUpdate(plugin.name, { configured: plugin.configured });
|
|
280
|
+
}
|
|
281
|
+
this.log.debug(`Configured all plugins for ${this.storeId}`);
|
|
259
282
|
}
|
|
260
283
|
else {
|
|
284
|
+
this.log.debug(`Starting plugin ${this.pluginName}...`);
|
|
261
285
|
await this.pluginManager.start(this.pluginName, 'Starting MatterNode');
|
|
262
|
-
this.
|
|
286
|
+
const plugin = this.pluginManager.get(this.pluginName);
|
|
287
|
+
this.pluginStatusUpdate(this.pluginName, { started: plugin?.started, registeredDevices: plugin?.registeredDevices });
|
|
288
|
+
this.log.debug(`Started plugin ${this.pluginName}...`);
|
|
289
|
+
this.log.debug(`Starting MatterNode for plugin ${this.storeId}...`);
|
|
263
290
|
await this.startServerNode();
|
|
264
|
-
this.log.debug(`Started MatterNode for plugin ${this.
|
|
291
|
+
this.log.debug(`Started MatterNode for plugin ${this.storeId}`);
|
|
292
|
+
this.log.debug(`Configuring plugin ${this.pluginName}...`);
|
|
265
293
|
await this.pluginManager.configure(this.pluginName);
|
|
294
|
+
this.pluginStatusUpdate(this.pluginName, { configured: this.pluginManager.get(this.pluginName)?.configured });
|
|
295
|
+
this.log.debug(`Configured plugin ${this.pluginName}...`);
|
|
266
296
|
}
|
|
267
|
-
this.log.debug(`Starting dependant MatterNodes...`);
|
|
297
|
+
this.log.debug(`Starting dependant MatterNodes for ${this.storeId}...`);
|
|
268
298
|
for (const dependantMatterNode of this.dependantMatterNodes.values()) {
|
|
269
299
|
await dependantMatterNode.start();
|
|
270
300
|
}
|
|
271
|
-
this.log.debug(`Started dependant MatterNodes`);
|
|
272
|
-
this.log.info(
|
|
301
|
+
this.log.debug(`Started dependant MatterNodes for ${this.storeId}`);
|
|
302
|
+
this.log.info(`Started MatterNode for ${this.storeId}`);
|
|
273
303
|
await this.yieldToNode();
|
|
274
304
|
}
|
|
275
305
|
async stop() {
|
|
276
306
|
if (!this.serverNode)
|
|
277
|
-
throw new Error(
|
|
278
|
-
this.log.info(
|
|
307
|
+
throw new Error(`Matter server node for ${this.storeId} not created yet. Call create() first.`);
|
|
308
|
+
this.log.info(`Stopping MatterNode for ${this.storeId}...`);
|
|
279
309
|
if (this.pluginName && this.device?.deviceName) {
|
|
280
310
|
this.log.debug(`Stopping MatterNode for server device ${this.pluginName}:${this.device.deviceName}...`);
|
|
281
311
|
await this.stopServerNode();
|
|
@@ -284,34 +314,34 @@ export class MatterNode extends EventEmitter {
|
|
|
284
314
|
await this.stopMatterStorage();
|
|
285
315
|
await this.destroy(false);
|
|
286
316
|
this.log.debug(`Stopped MatterNode for server device ${this.pluginName}:${this.device.deviceName}`);
|
|
287
|
-
this.log.info(
|
|
317
|
+
this.log.info(`Stopped MatterNode for ${this.storeId}`);
|
|
288
318
|
await this.yieldToNode();
|
|
289
319
|
return;
|
|
290
320
|
}
|
|
291
321
|
if (!this.pluginName) {
|
|
292
|
-
this.log.debug(
|
|
322
|
+
this.log.debug(`Stopping all plugins for ${this.storeId}...`);
|
|
293
323
|
const shutdownPromises = [];
|
|
294
324
|
for (const plugin of this.pluginManager.array().filter((p) => p.enabled && p.started)) {
|
|
295
325
|
shutdownPromises.push(this.pluginManager.shutdown(plugin, 'Stopping MatterNode'));
|
|
296
326
|
}
|
|
297
327
|
await Promise.all(shutdownPromises);
|
|
298
|
-
this.log.debug(
|
|
328
|
+
this.log.debug(`Stopped all plugins for ${this.storeId}`);
|
|
299
329
|
}
|
|
300
330
|
else {
|
|
301
331
|
this.log.debug(`Stopping plugin ${this.pluginName}...`);
|
|
302
332
|
await this.pluginManager.shutdown(this.pluginName, 'Stopping MatterNode');
|
|
303
333
|
this.log.debug(`Stopped plugin ${this.pluginName}`);
|
|
304
334
|
}
|
|
305
|
-
this.log.debug(`Stopping dependant MatterNodes...`);
|
|
335
|
+
this.log.debug(`Stopping dependant MatterNodes for ${this.storeId}...`);
|
|
306
336
|
for (const dependantMatterNode of this.dependantMatterNodes.values()) {
|
|
307
337
|
await dependantMatterNode.stop();
|
|
308
338
|
}
|
|
309
|
-
this.log.debug(`Stopped dependant MatterNodes`);
|
|
339
|
+
this.log.debug(`Stopped dependant MatterNodes for ${this.storeId}`);
|
|
310
340
|
await this.stopServerNode();
|
|
311
341
|
this.serverNode = undefined;
|
|
312
342
|
this.aggregatorNode = undefined;
|
|
313
343
|
await this.stopMatterStorage();
|
|
314
|
-
this.log.info(
|
|
344
|
+
this.log.info(`Stopped MatterNode for ${this.storeId}`);
|
|
315
345
|
await this.yieldToNode();
|
|
316
346
|
}
|
|
317
347
|
createDestinationMatterLogger() {
|
|
@@ -375,23 +405,28 @@ export class MatterNode extends EventEmitter {
|
|
|
375
405
|
const storageManager = await this.matterStorageService.open(storeId);
|
|
376
406
|
const storageContext = storageManager.createContext('persist');
|
|
377
407
|
const random = randomBytes(8).toString('hex');
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
await
|
|
384
|
-
await
|
|
385
|
-
await
|
|
386
|
-
await
|
|
387
|
-
await
|
|
388
|
-
await
|
|
389
|
-
await
|
|
390
|
-
await
|
|
391
|
-
await
|
|
392
|
-
await
|
|
393
|
-
await storageContext.
|
|
394
|
-
await storageContext.
|
|
408
|
+
async function setIfDifferent(key, value) {
|
|
409
|
+
if (!(await storageContext.has(key)) || (await storageContext.get(key)) !== value) {
|
|
410
|
+
await storageContext.set(key, value);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
await setIfDifferent('storeId', storeId);
|
|
414
|
+
await setIfDifferent('deviceName', deviceName);
|
|
415
|
+
await setIfDifferent('deviceType', deviceType);
|
|
416
|
+
await setIfDifferent('vendorId', vendorId);
|
|
417
|
+
await setIfDifferent('vendorName', vendorName.slice(0, 32));
|
|
418
|
+
await setIfDifferent('productId', productId);
|
|
419
|
+
await setIfDifferent('productName', productName.slice(0, 32));
|
|
420
|
+
await setIfDifferent('productLabel', productLabel.replace(vendorName, '').trim().slice(0, 64));
|
|
421
|
+
await setIfDifferent('productUrl', isValidString(productUrl, 8, 256) && productUrl.startsWith('https://') ? productUrl : 'https://matterbridge.io');
|
|
422
|
+
await setIfDifferent('nodeLabel', deviceName.slice(0, 32));
|
|
423
|
+
await setIfDifferent('serialNumber', await storageContext.get('serialNumber', serialNumber ? serialNumber.slice(0, 32) : 'SN' + random));
|
|
424
|
+
await setIfDifferent('uniqueId', await storageContext.get('uniqueId', uniqueId ? uniqueId.slice(0, 32) : 'UI' + random));
|
|
425
|
+
await setIfDifferent('softwareVersion', isValidInteger(softwareVersion, 0, UINT32_MAX) ? softwareVersion : 1);
|
|
426
|
+
await setIfDifferent('softwareVersionString', isValidString(softwareVersionString, 1, 64) ? softwareVersionString : '1.0.0');
|
|
427
|
+
await setIfDifferent('hardwareVersion', isValidInteger(hardwareVersion, 0, UINT16_MAX) ? hardwareVersion : 1);
|
|
428
|
+
await setIfDifferent('hardwareVersionString', isValidString(hardwareVersionString, 1, 64) ? hardwareVersionString : '1.0.0');
|
|
429
|
+
await setIfDifferent('configurationVersion', isValidInteger(configurationVersion, 1, UINT32_MAX) ? configurationVersion : 1);
|
|
395
430
|
this.log.debug(`Created server node storage context "${storeId}.persist" for ${storeId}:`);
|
|
396
431
|
this.log.debug(`- storeId: ${await storageContext.get('storeId')}`);
|
|
397
432
|
this.log.debug(`- deviceName: ${await storageContext.get('deviceName')}`);
|
|
@@ -626,7 +661,7 @@ export class MatterNode extends EventEmitter {
|
|
|
626
661
|
async createMatterbridgeServerNode() {
|
|
627
662
|
this.log.debug(`Creating ${plg}Matterbridge${db} server node...`);
|
|
628
663
|
this.matterStorageContext = await this.createServerNodeContext('Matterbridge', 'Matterbridge', this.aggregatorDeviceType, this.aggregatorVendorId, this.aggregatorVendorName, this.aggregatorProductId, this.aggregatorProductName, this.aggregatorSerialNumber, this.aggregatorUniqueId, parseVersionString(this.matterbridge.matterbridgeVersion), this.matterbridge.matterbridgeVersion, parseVersionString(this.matterbridge.systemInformation.osRelease), this.matterbridge.systemInformation.osRelease, 'Matter Bridge', 'https://matterbridge.io', 1);
|
|
629
|
-
this.serverNode = await this.createServerNode(this.port
|
|
664
|
+
this.serverNode = await this.createServerNode(this.port, this.passcode, this.discriminator);
|
|
630
665
|
this.aggregatorNode = await this.createAggregatorNode();
|
|
631
666
|
this.log.debug(`Adding ${plg}Matterbridge${db} aggregator node...`);
|
|
632
667
|
await this.serverNode.add(this.aggregatorNode);
|
|
@@ -647,7 +682,7 @@ export class MatterNode extends EventEmitter {
|
|
|
647
682
|
plugin.locked = true;
|
|
648
683
|
this.log.debug(`Creating accessory plugin ${plg}${plugin.name}${db} server node...`);
|
|
649
684
|
this.matterStorageContext = await this.createServerNodeContext(plugin.name, device.deviceName, DeviceTypeId(device.deviceType), VendorId(device.vendorId), device.vendorName, device.productId, device.productName, device.serialNumber, device.uniqueId, device.softwareVersion, device.softwareVersionString, device.hardwareVersion, device.hardwareVersionString, device.productLabel, device.productUrl, device.configurationVersion);
|
|
650
|
-
this.serverNode = await this.createServerNode(this.port
|
|
685
|
+
this.serverNode = await this.createServerNode(this.port, this.passcode, this.discriminator);
|
|
651
686
|
this.log.debug(`Adding ${plg}${plugin.name}${db}:${dev}${device.deviceName}${db} to ${plg}${plugin.name}${db} server node...`);
|
|
652
687
|
await this.serverNode.add(device);
|
|
653
688
|
this.log.debug(`Added ${plg}${plugin.name}${db}:${dev}${device.deviceName}${db} to ${plg}${plugin.name}${db} server node`);
|
|
@@ -668,7 +703,7 @@ export class MatterNode extends EventEmitter {
|
|
|
668
703
|
plugin.locked = true;
|
|
669
704
|
this.log.debug(`Creating dynamic plugin ${plg}${plugin.name}${db} server node...`);
|
|
670
705
|
this.matterStorageContext = await this.createServerNodeContext(plugin.name, plugin.description, this.aggregatorDeviceType, this.aggregatorVendorId, this.aggregatorVendorName, this.aggregatorProductId, this.aggregatorProductName, undefined, undefined, parseVersionString(this.matterbridge.matterbridgeVersion), this.matterbridge.matterbridgeVersion, parseVersionString(this.matterbridge.systemInformation.osRelease), this.matterbridge.systemInformation.osRelease, plugin.description, plugin.homepage ?? 'https://matterbridge.io', plugin.configurationVersion);
|
|
671
|
-
this.serverNode = await this.createServerNode(this.port
|
|
706
|
+
this.serverNode = await this.createServerNode(this.port, this.passcode, this.discriminator);
|
|
672
707
|
this.log.debug(`Creating dynamic plugin ${plg}${plugin.name}${db} aggregator node...`);
|
|
673
708
|
this.aggregatorNode = await this.createAggregatorNode();
|
|
674
709
|
this.log.debug(`Adding dynamic plugin ${plg}${plugin.name}${db} aggregator node...`);
|
|
@@ -690,7 +725,7 @@ export class MatterNode extends EventEmitter {
|
|
|
690
725
|
if (device.mode === 'server' && device.deviceType && device.deviceName && device.vendorId && device.vendorName && device.productId && device.productName) {
|
|
691
726
|
this.log.debug(`Creating device ${plg}${plugin.name}${db}:${dev}${device.deviceName}${db} server node...`);
|
|
692
727
|
this.matterStorageContext = await this.createServerNodeContext(device.deviceName.replace(/[ .]/g, ''), device.deviceName, DeviceTypeId(device.deviceType), VendorId(device.vendorId), device.vendorName, device.productId, device.productName, device.serialNumber, device.uniqueId, device.softwareVersion, device.softwareVersionString, device.hardwareVersion, device.hardwareVersionString, device.productLabel, device.productUrl, device.configurationVersion);
|
|
693
|
-
this.serverNode = await this.createServerNode(this.port
|
|
728
|
+
this.serverNode = await this.createServerNode(this.port, this.passcode, this.discriminator);
|
|
694
729
|
this.log.debug(`Adding ${plg}${plugin.name}${db}:${dev}${device.deviceName}${db} to server node...`);
|
|
695
730
|
await this.serverNode.add(device);
|
|
696
731
|
this.log.debug(`Added ${plg}${plugin.name}${db}:${dev}${device.deviceName}${db} to server node`);
|
|
@@ -708,9 +743,6 @@ export class MatterNode extends EventEmitter {
|
|
|
708
743
|
try {
|
|
709
744
|
this.log.debug(`Creating MatterNode for device ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} (${zb}${device.name}${db})...`);
|
|
710
745
|
const matterNode = new MatterNode(this.matterbridge, pluginName, device);
|
|
711
|
-
matterNode.port = this.port ? this.port++ : undefined;
|
|
712
|
-
matterNode.passcode = this.passcode ? this.passcode++ : undefined;
|
|
713
|
-
matterNode.discriminator = this.discriminator ? this.discriminator++ : undefined;
|
|
714
746
|
this.dependantMatterNodes.set(device.id, matterNode);
|
|
715
747
|
await matterNode.create();
|
|
716
748
|
this.log.debug(`Created MatterNode for device ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} (${zb}${device.name}${db})`);
|
|
@@ -1002,6 +1034,23 @@ export class MatterNode extends EventEmitter {
|
|
|
1002
1034
|
child.act((agent) => child.eventsOf(BridgedDeviceBasicInformationServer).reachableChanged.emit({ reachableNewValue: true }, agent.context));
|
|
1003
1035
|
}
|
|
1004
1036
|
}
|
|
1037
|
+
pluginStatusUpdate(pluginName, status) {
|
|
1038
|
+
this.server.request({ type: 'plugins_set', src: 'matter', dst: 'plugins', params: { plugin: { name: pluginName, ...status } } });
|
|
1039
|
+
this.server.request({
|
|
1040
|
+
type: 'frontend_broadcast_message',
|
|
1041
|
+
src: 'matter',
|
|
1042
|
+
dst: 'frontend',
|
|
1043
|
+
params: { msg: { id: 0, src: 'Matterbridge', dst: 'Frontend', method: 'plugin_status_update', success: true, response: { plugin: pluginName, status } } },
|
|
1044
|
+
});
|
|
1045
|
+
}
|
|
1046
|
+
matterbridgeStatusUpdate(status) {
|
|
1047
|
+
this.server.request({
|
|
1048
|
+
type: 'frontend_broadcast_message',
|
|
1049
|
+
src: 'matter',
|
|
1050
|
+
dst: 'frontend',
|
|
1051
|
+
params: { msg: { id: 0, src: 'Matterbridge', dst: 'Frontend', method: 'matterbridge_status_update', success: true, response: { status } } },
|
|
1052
|
+
});
|
|
1053
|
+
}
|
|
1005
1054
|
async yieldToNode(timeout = 10) {
|
|
1006
1055
|
await Promise.resolve();
|
|
1007
1056
|
await new Promise((resolve) => {
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { ServerNode, type SessionsBehavior } from '@matter/node';
|
|
2
2
|
import type { ExposedFabricInformation } from '@matter/protocol';
|
|
3
|
-
import type { ApiMatter, SanitizedExposedFabricInformation, SanitizedSession } from '@matterbridge/types';
|
|
3
|
+
import type { ApiDevice, ApiMatter, BaseDevice, SanitizedExposedFabricInformation, SanitizedSession } from '@matterbridge/types';
|
|
4
4
|
import type { MatterbridgeEndpoint } from './matterbridgeEndpoint.js';
|
|
5
|
+
export declare function toBaseDevice(device: MatterbridgeEndpoint | BaseDevice): BaseDevice;
|
|
6
|
+
export declare function toApiDevice(device: MatterbridgeEndpoint): ApiDevice | undefined;
|
|
5
7
|
export declare function getReachability(device: MatterbridgeEndpoint): boolean;
|
|
6
8
|
export declare function getPowerSource(endpoint: MatterbridgeEndpoint): 'ac' | 'dc' | 'ok' | 'warning' | 'critical' | undefined;
|
|
7
9
|
export declare function getBatteryLevel(endpoint: MatterbridgeEndpoint): number | undefined;
|
|
@@ -20,6 +20,54 @@ import { isValidArray, isValidNumber, isValidObject } from '@matterbridge/utils/
|
|
|
20
20
|
import { stringify } from 'node-ansi-logger';
|
|
21
21
|
import { featuresFor, getAttribute } from './matterbridgeEndpointHelpers.js';
|
|
22
22
|
const advertisingNodes = new Map();
|
|
23
|
+
export function toBaseDevice(device) {
|
|
24
|
+
return {
|
|
25
|
+
mode: device.mode,
|
|
26
|
+
plugin: device.plugin,
|
|
27
|
+
configUrl: device.configUrl,
|
|
28
|
+
deviceName: device.deviceName,
|
|
29
|
+
serialNumber: device.serialNumber,
|
|
30
|
+
uniqueId: device.uniqueId,
|
|
31
|
+
vendorId: device.vendorId,
|
|
32
|
+
vendorName: device.vendorName,
|
|
33
|
+
productId: device.productId,
|
|
34
|
+
productName: device.productName,
|
|
35
|
+
productLabel: device.productLabel,
|
|
36
|
+
productUrl: device.productUrl,
|
|
37
|
+
configurationVersion: device.configurationVersion,
|
|
38
|
+
softwareVersion: device.softwareVersion,
|
|
39
|
+
softwareVersionString: device.softwareVersionString,
|
|
40
|
+
hardwareVersion: device.hardwareVersion,
|
|
41
|
+
hardwareVersionString: device.hardwareVersionString,
|
|
42
|
+
tagList: device.tagList,
|
|
43
|
+
originalId: device.originalId,
|
|
44
|
+
name: device.name,
|
|
45
|
+
deviceType: device.deviceType,
|
|
46
|
+
deviceTypes: device.deviceTypes instanceof Map ? Array.from(device.deviceTypes.keys()) : device.deviceTypes,
|
|
47
|
+
number: device.number,
|
|
48
|
+
id: device.id,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
export function toApiDevice(device) {
|
|
52
|
+
if (!device.plugin || !device.deviceType || !device.name || !device.deviceName || !device.serialNumber || !device.uniqueId || !device.lifecycle.isReady)
|
|
53
|
+
return undefined;
|
|
54
|
+
return {
|
|
55
|
+
plugin: device.plugin,
|
|
56
|
+
type: device.name + ' (0x' + device.deviceType.toString(16).padStart(4, '0') + ')',
|
|
57
|
+
number: device.number,
|
|
58
|
+
id: device.id,
|
|
59
|
+
deviceName: device.deviceName,
|
|
60
|
+
serialNumber: device.serialNumber,
|
|
61
|
+
productUrl: device.productUrl,
|
|
62
|
+
configUrl: device.configUrl,
|
|
63
|
+
uniqueId: device.uniqueId,
|
|
64
|
+
reachable: getReachability(device),
|
|
65
|
+
powerSource: getPowerSource(device),
|
|
66
|
+
batteryLevel: getBatteryLevel(device),
|
|
67
|
+
matter: device.mode === 'server' && device.serverNode ? getServerNodeData(device.serverNode) : undefined,
|
|
68
|
+
cluster: getClusterTextFromDevice(device),
|
|
69
|
+
};
|
|
70
|
+
}
|
|
23
71
|
export function getReachability(device) {
|
|
24
72
|
if (!device.lifecycle.isReady || device.construction.status !== Lifecycle.Status.Active)
|
|
25
73
|
return false;
|
package/dist/matterbridge.js
CHANGED
|
@@ -16,7 +16,7 @@ import { DeviceTypeId, EndpointNumber, VendorId } from '@matter/types/datatype';
|
|
|
16
16
|
import { ManualPairingCodeCodec } from '@matter/types/schema';
|
|
17
17
|
import { BroadcastServer } from '@matterbridge/thread/server';
|
|
18
18
|
import { dev, MATTER_LOGGER_FILE, MATTER_STORAGE_DIR, MATTERBRIDGE_LOGGER_FILE, NODE_STORAGE_DIR, plg, typ } from '@matterbridge/types';
|
|
19
|
-
import { isBun, getGlobalBunModules, memoryFootprint } from '@matterbridge/utils/bun';
|
|
19
|
+
import { constrainedMemory, isBun, getGlobalBunModules, memoryFootprint } from '@matterbridge/utils/bun';
|
|
20
20
|
import { getIntParameter, getParameter, hasAnyParameter, hasParameter } from '@matterbridge/utils/cli';
|
|
21
21
|
import { copyDirectory } from '@matterbridge/utils/copy-dir';
|
|
22
22
|
import { createDirectory } from '@matterbridge/utils/create-dir';
|
|
@@ -53,6 +53,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
53
53
|
osArch: '',
|
|
54
54
|
totalMemory: '',
|
|
55
55
|
freeMemory: '',
|
|
56
|
+
constrainedMemory: '',
|
|
56
57
|
systemUptime: '',
|
|
57
58
|
processUptime: '',
|
|
58
59
|
cpuUsage: '',
|
|
@@ -171,6 +172,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
171
172
|
}
|
|
172
173
|
getPlatformMatterbridge() {
|
|
173
174
|
this.systemInformation.totalMemory = formatBytes(os.totalmem());
|
|
175
|
+
this.systemInformation.constrainedMemory = formatBytes(constrainedMemory());
|
|
174
176
|
this.systemInformation.freeMemory = formatBytes(os.freemem());
|
|
175
177
|
this.systemInformation.systemUptime = formatUptime(os.uptime());
|
|
176
178
|
this.systemInformation.processUptime = formatUptime(Math.floor(process.uptime()));
|
|
@@ -201,6 +203,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
201
203
|
}
|
|
202
204
|
getSharedMatterbridge() {
|
|
203
205
|
this.systemInformation.totalMemory = formatBytes(os.totalmem());
|
|
206
|
+
this.systemInformation.constrainedMemory = formatBytes(constrainedMemory());
|
|
204
207
|
this.systemInformation.freeMemory = formatBytes(os.freemem());
|
|
205
208
|
this.systemInformation.systemUptime = formatUptime(os.uptime());
|
|
206
209
|
this.systemInformation.processUptime = formatUptime(Math.floor(process.uptime()));
|
|
@@ -246,6 +249,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
246
249
|
}
|
|
247
250
|
getApiSettings() {
|
|
248
251
|
this.systemInformation.totalMemory = formatBytes(os.totalmem());
|
|
252
|
+
this.systemInformation.constrainedMemory = formatBytes(constrainedMemory());
|
|
249
253
|
this.systemInformation.freeMemory = formatBytes(os.freemem());
|
|
250
254
|
this.systemInformation.systemUptime = formatUptime(os.uptime());
|
|
251
255
|
this.systemInformation.processUptime = formatUptime(Math.floor(process.uptime()));
|
|
@@ -275,9 +279,6 @@ export class Matterbridge extends EventEmitter {
|
|
|
275
279
|
bridgeStatus: this.bridgeStatus,
|
|
276
280
|
profile: this.profile,
|
|
277
281
|
readOnly: hasParameter('readonly'),
|
|
278
|
-
shellyBoard: false,
|
|
279
|
-
shellySysUpdate: false,
|
|
280
|
-
shellyMainUpdate: false,
|
|
281
282
|
loggerLevel: this.logLevel,
|
|
282
283
|
fileLogger: this.fileLogger,
|
|
283
284
|
matterLoggerLevel: this.matterLogLevel,
|
|
@@ -299,7 +300,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
299
300
|
};
|
|
300
301
|
}
|
|
301
302
|
async msgHandler(msg) {
|
|
302
|
-
if (this.server.isWorkerRequest(msg)
|
|
303
|
+
if (this.server.isWorkerRequest(msg)) {
|
|
303
304
|
if (this.verbose)
|
|
304
305
|
this.log.debug(`Received broadcast request ${CYAN}${msg.type}${db} from ${CYAN}${msg.src}${db}: ${debugStringify(msg)}${db}`);
|
|
305
306
|
switch (msg.type) {
|
|
@@ -355,21 +356,6 @@ export class Matterbridge extends EventEmitter {
|
|
|
355
356
|
this.server.respond({ ...msg, result: { success: true } });
|
|
356
357
|
await this.shutdownProcess();
|
|
357
358
|
break;
|
|
358
|
-
case 'matterbridge_apimatter': {
|
|
359
|
-
let serverNode;
|
|
360
|
-
if (msg.params.id === 'Matterbridge')
|
|
361
|
-
serverNode = this.serverNode;
|
|
362
|
-
else
|
|
363
|
-
serverNode =
|
|
364
|
-
this.plugins.array().find((p) => p.serverNode && p.serverNode.id === msg.params.id)?.serverNode ??
|
|
365
|
-
this.devices.array().find((d) => d.serverNode && d.serverNode.id === msg.params.id)?.serverNode;
|
|
366
|
-
if (!serverNode) {
|
|
367
|
-
this.server.respond({ ...msg, result: { matter: undefined } });
|
|
368
|
-
break;
|
|
369
|
-
}
|
|
370
|
-
this.server.respond({ ...msg, result: { matter: getServerNodeData(serverNode) } });
|
|
371
|
-
break;
|
|
372
|
-
}
|
|
373
359
|
case 'matterbridge_apisettings':
|
|
374
360
|
this.server.respond({ ...msg, result: { data: this.getApiSettings(), success: true } });
|
|
375
361
|
break;
|
|
@@ -474,6 +460,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
474
460
|
this.environment.vars.set('path.root', path.join(this.matterbridgeDirectory, MATTER_STORAGE_DIR));
|
|
475
461
|
this.environment.vars.set('runtime.signals', false);
|
|
476
462
|
this.environment.vars.set('runtime.exitcode', false);
|
|
463
|
+
this.environment.vars.set('endpoint.validation', 'strict');
|
|
477
464
|
this.registerProcessHandlers();
|
|
478
465
|
try {
|
|
479
466
|
this.log.debug(`Creating node storage manager: ${CYAN}${NODE_STORAGE_DIR}${db}`);
|
|
@@ -1204,6 +1191,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
1204
1191
|
this.systemInformation.osPlatform = os.platform();
|
|
1205
1192
|
this.systemInformation.osArch = os.arch();
|
|
1206
1193
|
this.systemInformation.totalMemory = formatBytes(os.totalmem());
|
|
1194
|
+
this.systemInformation.constrainedMemory = formatBytes(constrainedMemory());
|
|
1207
1195
|
this.systemInformation.freeMemory = formatBytes(os.freemem());
|
|
1208
1196
|
this.systemInformation.systemUptime = formatUptime(os.uptime());
|
|
1209
1197
|
this.systemInformation.processUptime = formatUptime(process.uptime());
|
|
@@ -1226,6 +1214,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
1226
1214
|
this.log.debug(`- Architecture: ${this.systemInformation.osArch}`);
|
|
1227
1215
|
this.log.debug(`- Total Memory: ${this.systemInformation.totalMemory}`);
|
|
1228
1216
|
this.log.debug(`- Free Memory: ${this.systemInformation.freeMemory}`);
|
|
1217
|
+
this.log.debug(`- Constrained Memory: ${this.systemInformation.constrainedMemory}`);
|
|
1229
1218
|
this.log.debug(`- System Uptime: ${this.systemInformation.systemUptime}`);
|
|
1230
1219
|
this.log.debug(`- Process Uptime: ${this.systemInformation.processUptime}`);
|
|
1231
1220
|
this.log.debug(`- RSS: ${this.systemInformation.rss}`);
|
|
@@ -1400,6 +1389,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
1400
1389
|
this.reachabilityTimeout = undefined;
|
|
1401
1390
|
this.log.debug('Matterbridge reachability timeout cleared');
|
|
1402
1391
|
}
|
|
1392
|
+
this.server.request({ type: 'manager_shutdown', src: 'matterbridge', dst: 'manager', params: {} });
|
|
1403
1393
|
for (const plugin of this.plugins) {
|
|
1404
1394
|
if (!plugin.enabled || plugin.error)
|
|
1405
1395
|
continue;
|
|
@@ -1530,12 +1520,12 @@ export class Matterbridge extends EventEmitter {
|
|
|
1530
1520
|
this.log.info(`Matterbridge has run ${CYAN}${this.runningTimes}${nf} times for a total of ${CYAN}${this.runningDays}${nf} days`);
|
|
1531
1521
|
this.log.info(`Matterbridge last started at ${CYAN}${new Date(this.startupAt).toLocaleString()}${nf} and shut down at ${CYAN}${new Date(this.shutdownAt).toLocaleString()}${nf}`);
|
|
1532
1522
|
}
|
|
1533
|
-
|
|
1534
|
-
|
|
1523
|
+
if (!hasParameter('experimental-backend')) {
|
|
1524
|
+
await this.frontend.stop();
|
|
1525
|
+
this.frontend.destroy();
|
|
1526
|
+
}
|
|
1535
1527
|
this.plugins.destroy();
|
|
1536
1528
|
this.devices.destroy();
|
|
1537
|
-
this.server.request({ type: 'manager_shutdown', src: 'matterbridge', dst: 'manager', params: {} });
|
|
1538
|
-
await wait(100);
|
|
1539
1529
|
this.server.close();
|
|
1540
1530
|
if (this.nodeStorage && this.nodeContext) {
|
|
1541
1531
|
this.log.debug(`Closing node storage context for ${plg}Matterbridge${db}...`);
|