matterbridge 3.2.4 → 3.2.5-dev-20250831-732330c
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 +21 -2
- package/dist/cli.js +2 -91
- package/dist/cliEmitter.js +0 -30
- package/dist/clusters/export.js +0 -2
- package/dist/defaultConfigSchema.js +0 -24
- package/dist/deviceManager.js +1 -94
- package/dist/devices/batteryStorage.js +1 -48
- package/dist/devices/cooktop.js +0 -55
- package/dist/devices/dishwasher.js +0 -57
- package/dist/devices/evse.js +10 -74
- package/dist/devices/export.js +0 -4
- package/dist/devices/extractorHood.js +0 -42
- package/dist/devices/heatPump.js +2 -50
- package/dist/devices/laundryDryer.js +3 -62
- package/dist/devices/laundryWasher.js +4 -70
- package/dist/devices/microwaveOven.js +5 -88
- package/dist/devices/oven.js +0 -85
- package/dist/devices/refrigerator.js +32 -83
- package/dist/devices/roboticVacuumCleaner.js +7 -93
- package/dist/devices/solarPower.js +0 -38
- package/dist/devices/temperatureControl.js +3 -25
- package/dist/devices/waterHeater.js +2 -82
- package/dist/dgram/coap.js +13 -126
- package/dist/dgram/dgram.js +2 -113
- package/dist/dgram/mb_coap.js +3 -41
- package/dist/dgram/mb_mdns.js +13 -51
- package/dist/dgram/mdns.js +137 -298
- package/dist/dgram/multicast.js +1 -60
- package/dist/dgram/unicast.js +0 -54
- package/dist/frontend.js +24 -451
- package/dist/globalMatterbridge.js +0 -47
- package/dist/helpers.js +0 -53
- package/dist/index.js +1 -30
- package/dist/logger/export.js +0 -1
- package/dist/matter/behaviors.js +0 -2
- package/dist/matter/clusters.js +0 -2
- package/dist/matter/devices.js +0 -2
- package/dist/matter/endpoints.js +0 -2
- package/dist/matter/export.js +0 -3
- package/dist/matter/types.js +0 -3
- package/dist/matterbridge.js +50 -789
- package/dist/matterbridgeAccessoryPlatform.js +0 -36
- package/dist/matterbridgeBehaviors.js +5 -65
- package/dist/matterbridgeDeviceTypes.js +15 -579
- package/dist/matterbridgeDynamicPlatform.js +0 -36
- package/dist/matterbridgeEndpoint.js +54 -1220
- package/dist/matterbridgeEndpointHelpers.js +12 -345
- package/dist/matterbridgePlatform.js +0 -256
- package/dist/matterbridgeTypes.js +0 -25
- package/dist/pluginManager.js +3 -249
- package/dist/shelly.js +7 -168
- package/dist/storage/export.js +0 -1
- package/dist/update.js +0 -69
- package/dist/utils/colorUtils.js +2 -97
- package/dist/utils/commandLine.js +0 -54
- package/dist/utils/copyDirectory.js +1 -38
- package/dist/utils/createDirectory.js +0 -33
- package/dist/utils/createZip.js +2 -47
- package/dist/utils/deepCopy.js +0 -39
- package/dist/utils/deepEqual.js +1 -72
- package/dist/utils/error.js +0 -41
- package/dist/utils/export.js +0 -1
- package/dist/utils/hex.js +0 -124
- package/dist/utils/isvalid.js +0 -101
- package/dist/utils/network.js +5 -91
- package/dist/utils/spawn.js +0 -40
- package/dist/utils/wait.js +8 -60
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -2
- package/dist/cli.d.ts +0 -26
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/cliEmitter.d.ts +0 -34
- package/dist/cliEmitter.d.ts.map +0 -1
- package/dist/cliEmitter.js.map +0 -1
- package/dist/clusters/export.d.ts +0 -2
- package/dist/clusters/export.d.ts.map +0 -1
- package/dist/clusters/export.js.map +0 -1
- package/dist/defaultConfigSchema.d.ts +0 -28
- package/dist/defaultConfigSchema.d.ts.map +0 -1
- package/dist/defaultConfigSchema.js.map +0 -1
- package/dist/deviceManager.d.ts +0 -112
- package/dist/deviceManager.d.ts.map +0 -1
- package/dist/deviceManager.js.map +0 -1
- package/dist/devices/batteryStorage.d.ts +0 -48
- package/dist/devices/batteryStorage.d.ts.map +0 -1
- package/dist/devices/batteryStorage.js.map +0 -1
- package/dist/devices/cooktop.d.ts +0 -60
- package/dist/devices/cooktop.d.ts.map +0 -1
- package/dist/devices/cooktop.js.map +0 -1
- package/dist/devices/dishwasher.d.ts +0 -71
- package/dist/devices/dishwasher.d.ts.map +0 -1
- package/dist/devices/dishwasher.js.map +0 -1
- package/dist/devices/evse.d.ts +0 -75
- package/dist/devices/evse.d.ts.map +0 -1
- package/dist/devices/evse.js.map +0 -1
- package/dist/devices/export.d.ts +0 -15
- package/dist/devices/export.d.ts.map +0 -1
- package/dist/devices/export.js.map +0 -1
- package/dist/devices/extractorHood.d.ts +0 -46
- package/dist/devices/extractorHood.d.ts.map +0 -1
- package/dist/devices/extractorHood.js.map +0 -1
- package/dist/devices/heatPump.d.ts +0 -47
- package/dist/devices/heatPump.d.ts.map +0 -1
- package/dist/devices/heatPump.js.map +0 -1
- package/dist/devices/laundryDryer.d.ts +0 -67
- package/dist/devices/laundryDryer.d.ts.map +0 -1
- package/dist/devices/laundryDryer.js.map +0 -1
- package/dist/devices/laundryWasher.d.ts +0 -81
- package/dist/devices/laundryWasher.d.ts.map +0 -1
- package/dist/devices/laundryWasher.js.map +0 -1
- package/dist/devices/microwaveOven.d.ts +0 -168
- package/dist/devices/microwaveOven.d.ts.map +0 -1
- package/dist/devices/microwaveOven.js.map +0 -1
- package/dist/devices/oven.d.ts +0 -105
- package/dist/devices/oven.d.ts.map +0 -1
- package/dist/devices/oven.js.map +0 -1
- package/dist/devices/refrigerator.d.ts +0 -93
- package/dist/devices/refrigerator.d.ts.map +0 -1
- package/dist/devices/refrigerator.js.map +0 -1
- package/dist/devices/roboticVacuumCleaner.d.ts +0 -112
- package/dist/devices/roboticVacuumCleaner.d.ts.map +0 -1
- package/dist/devices/roboticVacuumCleaner.js.map +0 -1
- package/dist/devices/solarPower.d.ts +0 -40
- package/dist/devices/solarPower.d.ts.map +0 -1
- package/dist/devices/solarPower.js.map +0 -1
- package/dist/devices/temperatureControl.d.ts +0 -166
- package/dist/devices/temperatureControl.d.ts.map +0 -1
- package/dist/devices/temperatureControl.js.map +0 -1
- package/dist/devices/waterHeater.d.ts +0 -111
- package/dist/devices/waterHeater.d.ts.map +0 -1
- package/dist/devices/waterHeater.js.map +0 -1
- package/dist/dgram/coap.d.ts +0 -205
- package/dist/dgram/coap.d.ts.map +0 -1
- package/dist/dgram/coap.js.map +0 -1
- package/dist/dgram/dgram.d.ts +0 -140
- package/dist/dgram/dgram.d.ts.map +0 -1
- package/dist/dgram/dgram.js.map +0 -1
- package/dist/dgram/mb_coap.d.ts +0 -24
- package/dist/dgram/mb_coap.d.ts.map +0 -1
- package/dist/dgram/mb_coap.js.map +0 -1
- package/dist/dgram/mb_mdns.d.ts +0 -24
- package/dist/dgram/mb_mdns.d.ts.map +0 -1
- package/dist/dgram/mb_mdns.js.map +0 -1
- package/dist/dgram/mdns.d.ts +0 -288
- package/dist/dgram/mdns.d.ts.map +0 -1
- package/dist/dgram/mdns.js.map +0 -1
- package/dist/dgram/multicast.d.ts +0 -65
- package/dist/dgram/multicast.d.ts.map +0 -1
- package/dist/dgram/multicast.js.map +0 -1
- package/dist/dgram/unicast.d.ts +0 -56
- package/dist/dgram/unicast.d.ts.map +0 -1
- package/dist/dgram/unicast.js.map +0 -1
- package/dist/frontend.d.ts +0 -313
- package/dist/frontend.d.ts.map +0 -1
- package/dist/frontend.js.map +0 -1
- package/dist/globalMatterbridge.d.ts +0 -59
- package/dist/globalMatterbridge.d.ts.map +0 -1
- package/dist/globalMatterbridge.js.map +0 -1
- package/dist/helpers.d.ts +0 -48
- package/dist/helpers.d.ts.map +0 -1
- package/dist/helpers.js.map +0 -1
- package/dist/index.d.ts +0 -33
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/logger/export.d.ts +0 -2
- package/dist/logger/export.d.ts.map +0 -1
- package/dist/logger/export.js.map +0 -1
- package/dist/matter/behaviors.d.ts +0 -2
- package/dist/matter/behaviors.d.ts.map +0 -1
- package/dist/matter/behaviors.js.map +0 -1
- package/dist/matter/clusters.d.ts +0 -2
- package/dist/matter/clusters.d.ts.map +0 -1
- package/dist/matter/clusters.js.map +0 -1
- package/dist/matter/devices.d.ts +0 -2
- package/dist/matter/devices.d.ts.map +0 -1
- package/dist/matter/devices.js.map +0 -1
- package/dist/matter/endpoints.d.ts +0 -2
- package/dist/matter/endpoints.d.ts.map +0 -1
- package/dist/matter/endpoints.js.map +0 -1
- package/dist/matter/export.d.ts +0 -5
- package/dist/matter/export.d.ts.map +0 -1
- package/dist/matter/export.js.map +0 -1
- package/dist/matter/types.d.ts +0 -3
- package/dist/matter/types.d.ts.map +0 -1
- package/dist/matter/types.js.map +0 -1
- package/dist/matterbridge.d.ts +0 -462
- package/dist/matterbridge.d.ts.map +0 -1
- package/dist/matterbridge.js.map +0 -1
- package/dist/matterbridgeAccessoryPlatform.d.ts +0 -42
- package/dist/matterbridgeAccessoryPlatform.d.ts.map +0 -1
- package/dist/matterbridgeAccessoryPlatform.js.map +0 -1
- package/dist/matterbridgeBehaviors.d.ts +0 -1351
- package/dist/matterbridgeBehaviors.d.ts.map +0 -1
- package/dist/matterbridgeBehaviors.js.map +0 -1
- package/dist/matterbridgeDeviceTypes.d.ts +0 -709
- package/dist/matterbridgeDeviceTypes.d.ts.map +0 -1
- package/dist/matterbridgeDeviceTypes.js.map +0 -1
- package/dist/matterbridgeDynamicPlatform.d.ts +0 -42
- package/dist/matterbridgeDynamicPlatform.d.ts.map +0 -1
- package/dist/matterbridgeDynamicPlatform.js.map +0 -1
- package/dist/matterbridgeEndpoint.d.ts +0 -1356
- package/dist/matterbridgeEndpoint.d.ts.map +0 -1
- package/dist/matterbridgeEndpoint.js.map +0 -1
- package/dist/matterbridgeEndpointHelpers.d.ts +0 -407
- package/dist/matterbridgeEndpointHelpers.d.ts.map +0 -1
- package/dist/matterbridgeEndpointHelpers.js.map +0 -1
- package/dist/matterbridgePlatform.d.ts +0 -331
- package/dist/matterbridgePlatform.d.ts.map +0 -1
- package/dist/matterbridgePlatform.js.map +0 -1
- package/dist/matterbridgeTypes.d.ts +0 -198
- package/dist/matterbridgeTypes.d.ts.map +0 -1
- package/dist/matterbridgeTypes.js.map +0 -1
- package/dist/pluginManager.d.ts +0 -270
- package/dist/pluginManager.d.ts.map +0 -1
- package/dist/pluginManager.js.map +0 -1
- package/dist/shelly.d.ts +0 -174
- package/dist/shelly.d.ts.map +0 -1
- package/dist/shelly.js.map +0 -1
- package/dist/storage/export.d.ts +0 -2
- package/dist/storage/export.d.ts.map +0 -1
- package/dist/storage/export.js.map +0 -1
- package/dist/update.d.ts +0 -75
- package/dist/update.d.ts.map +0 -1
- package/dist/update.js.map +0 -1
- package/dist/utils/colorUtils.d.ts +0 -99
- package/dist/utils/colorUtils.d.ts.map +0 -1
- package/dist/utils/colorUtils.js.map +0 -1
- package/dist/utils/commandLine.d.ts +0 -59
- package/dist/utils/commandLine.d.ts.map +0 -1
- package/dist/utils/commandLine.js.map +0 -1
- package/dist/utils/copyDirectory.d.ts +0 -33
- package/dist/utils/copyDirectory.d.ts.map +0 -1
- package/dist/utils/copyDirectory.js.map +0 -1
- package/dist/utils/createDirectory.d.ts +0 -34
- package/dist/utils/createDirectory.d.ts.map +0 -1
- package/dist/utils/createDirectory.js.map +0 -1
- package/dist/utils/createZip.d.ts +0 -39
- package/dist/utils/createZip.d.ts.map +0 -1
- package/dist/utils/createZip.js.map +0 -1
- package/dist/utils/deepCopy.d.ts +0 -32
- package/dist/utils/deepCopy.d.ts.map +0 -1
- package/dist/utils/deepCopy.js.map +0 -1
- package/dist/utils/deepEqual.d.ts +0 -54
- package/dist/utils/deepEqual.d.ts.map +0 -1
- package/dist/utils/deepEqual.js.map +0 -1
- package/dist/utils/error.d.ts +0 -44
- package/dist/utils/error.d.ts.map +0 -1
- package/dist/utils/error.js.map +0 -1
- package/dist/utils/export.d.ts +0 -12
- package/dist/utils/export.d.ts.map +0 -1
- package/dist/utils/export.js.map +0 -1
- package/dist/utils/hex.d.ts +0 -89
- package/dist/utils/hex.d.ts.map +0 -1
- package/dist/utils/hex.js.map +0 -1
- package/dist/utils/isvalid.d.ts +0 -103
- package/dist/utils/isvalid.d.ts.map +0 -1
- package/dist/utils/isvalid.js.map +0 -1
- package/dist/utils/network.d.ts +0 -84
- package/dist/utils/network.d.ts.map +0 -1
- package/dist/utils/network.js.map +0 -1
- package/dist/utils/spawn.d.ts +0 -33
- package/dist/utils/spawn.d.ts.map +0 -1
- package/dist/utils/spawn.js.map +0 -1
- package/dist/utils/wait.d.ts +0 -54
- package/dist/utils/wait.d.ts.map +0 -1
- package/dist/utils/wait.js.map +0 -1
package/dist/matterbridge.js
CHANGED
|
@@ -1,43 +1,15 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* This file contains the class Matterbridge.
|
|
3
|
-
*
|
|
4
|
-
* @file matterbridge.ts
|
|
5
|
-
* @author Luca Liguori
|
|
6
|
-
* @created 2023-12-29
|
|
7
|
-
* @version 1.6.0
|
|
8
|
-
* @license Apache-2.0
|
|
9
|
-
*
|
|
10
|
-
* Copyright 2023, 2024, 2025 Luca Liguori.
|
|
11
|
-
*
|
|
12
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
13
|
-
* you may not use this file except in compliance with the License.
|
|
14
|
-
* You may obtain a copy of the License at
|
|
15
|
-
*
|
|
16
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
17
|
-
*
|
|
18
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
19
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
20
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
21
|
-
* See the License for the specific language governing permissions and
|
|
22
|
-
* limitations under the License.
|
|
23
|
-
*/
|
|
24
|
-
// Node.js modules
|
|
25
1
|
import os from 'node:os';
|
|
26
2
|
import path from 'node:path';
|
|
27
3
|
import { promises as fs } from 'node:fs';
|
|
28
4
|
import EventEmitter from 'node:events';
|
|
29
5
|
import { inspect } from 'node:util';
|
|
30
|
-
// AnsiLogger module
|
|
31
6
|
import { AnsiLogger, UNDERLINE, UNDERLINEOFF, db, debugStringify, BRIGHT, RESET, er, nf, rs, wr, RED, GREEN, zb, CYAN, nt, BLUE } from 'node-ansi-logger';
|
|
32
|
-
// NodeStorage module
|
|
33
7
|
import { NodeStorageManager } from 'node-persist-manager';
|
|
34
|
-
// @matter
|
|
35
8
|
import { DeviceTypeId, Endpoint, Logger, LogLevel as MatterLogLevel, LogFormat as MatterLogFormat, VendorId, StorageService, Environment, ServerNode, UINT32_MAX, UINT16_MAX, Crypto, } from '@matter/main';
|
|
36
9
|
import { DeviceCommissioner, FabricAction, MdnsService, PaseClient } from '@matter/main/protocol';
|
|
37
10
|
import { AggregatorEndpoint } from '@matter/main/endpoints';
|
|
38
11
|
import { BasicInformationServer } from '@matter/main/behaviors/basic-information';
|
|
39
12
|
import { BridgedDeviceBasicInformationServer } from '@matter/main/behaviors/bridged-device-basic-information';
|
|
40
|
-
// Matterbridge
|
|
41
13
|
import { getParameter, getIntParameter, hasParameter, copyDirectory, isValidString, parseVersionString, isValidNumber, createDirectory } from './utils/export.js';
|
|
42
14
|
import { withTimeout, waiter, wait } from './utils/wait.js';
|
|
43
15
|
import { dev, plg, typ } from './matterbridgeTypes.js';
|
|
@@ -47,9 +19,6 @@ import { MatterbridgeEndpoint } from './matterbridgeEndpoint.js';
|
|
|
47
19
|
import { bridge } from './matterbridgeDeviceTypes.js';
|
|
48
20
|
import { Frontend } from './frontend.js';
|
|
49
21
|
import { addVirtualDevices } from './helpers.js';
|
|
50
|
-
/**
|
|
51
|
-
* Represents the Matterbridge application.
|
|
52
|
-
*/
|
|
53
22
|
export class Matterbridge extends EventEmitter {
|
|
54
23
|
systemInformation = {
|
|
55
24
|
interfaceName: '',
|
|
@@ -98,7 +67,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
98
67
|
shellySysUpdate: false,
|
|
99
68
|
shellyMainUpdate: false,
|
|
100
69
|
profile: getParameter('profile'),
|
|
101
|
-
loggerLevel: "info"
|
|
70
|
+
loggerLevel: "info",
|
|
102
71
|
fileLogger: false,
|
|
103
72
|
matterLoggerLevel: MatterLogLevel.INFO,
|
|
104
73
|
matterFileLogger: false,
|
|
@@ -126,18 +95,15 @@ export class Matterbridge extends EventEmitter {
|
|
|
126
95
|
profile = getParameter('profile');
|
|
127
96
|
shutdown = false;
|
|
128
97
|
failCountLimit = hasParameter('shelly') ? 600 : 120;
|
|
129
|
-
|
|
130
|
-
log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: hasParameter('debug') ? "debug" /* LogLevel.DEBUG */ : "info" /* LogLevel.INFO */ });
|
|
98
|
+
log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4, logLevel: hasParameter('debug') ? "debug" : "info" });
|
|
131
99
|
matterbridgeLoggerFile = 'matterbridge' + (getParameter('profile') ? '.' + getParameter('profile') : '') + '.log';
|
|
132
100
|
matterLoggerFile = 'matter' + (getParameter('profile') ? '.' + getParameter('profile') : '') + '.log';
|
|
133
101
|
plugins = new PluginManager(this);
|
|
134
102
|
devices = new DeviceManager(this);
|
|
135
103
|
frontend = new Frontend(this);
|
|
136
|
-
// Matterbridge storage
|
|
137
104
|
nodeStorageName = 'storage' + (getParameter('profile') ? '.' + getParameter('profile') : '');
|
|
138
105
|
nodeStorage;
|
|
139
106
|
nodeContext;
|
|
140
|
-
// Cleanup
|
|
141
107
|
hasCleanupStarted = false;
|
|
142
108
|
initialized = false;
|
|
143
109
|
startMatterInterval;
|
|
@@ -151,23 +117,19 @@ export class Matterbridge extends EventEmitter {
|
|
|
151
117
|
sigtermHandler;
|
|
152
118
|
exceptionHandler;
|
|
153
119
|
rejectionHandler;
|
|
154
|
-
// Matter environment
|
|
155
120
|
environment = Environment.default;
|
|
156
|
-
// Matter storage
|
|
157
121
|
matterStorageName = 'matterstorage' + (getParameter('profile') ? '.' + getParameter('profile') : '');
|
|
158
122
|
matterStorageService;
|
|
159
123
|
matterStorageManager;
|
|
160
124
|
matterbridgeContext;
|
|
161
125
|
controllerContext;
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
certification; // device certification
|
|
170
|
-
// Matter nodes
|
|
126
|
+
mdnsInterface;
|
|
127
|
+
ipv4address;
|
|
128
|
+
ipv6address;
|
|
129
|
+
port;
|
|
130
|
+
passcode;
|
|
131
|
+
discriminator;
|
|
132
|
+
certification;
|
|
171
133
|
serverNode;
|
|
172
134
|
aggregatorNode;
|
|
173
135
|
aggregatorVendorId = VendorId(getIntParameter('vendorId') ?? 0xfff1);
|
|
@@ -178,31 +140,15 @@ export class Matterbridge extends EventEmitter {
|
|
|
178
140
|
aggregatorSerialNumber = getParameter('serialNumber');
|
|
179
141
|
aggregatorUniqueId = getParameter('uniqueId');
|
|
180
142
|
static instance;
|
|
181
|
-
// We load asyncronously so is private
|
|
182
143
|
constructor() {
|
|
183
144
|
super();
|
|
184
145
|
}
|
|
185
|
-
/**
|
|
186
|
-
* Retrieves the list of Matterbridge devices.
|
|
187
|
-
*
|
|
188
|
-
* @returns {MatterbridgeEndpoint[]} An array of MatterbridgeDevice objects.
|
|
189
|
-
*/
|
|
190
146
|
getDevices() {
|
|
191
147
|
return this.devices.array();
|
|
192
148
|
}
|
|
193
|
-
/**
|
|
194
|
-
* Retrieves the list of registered plugins.
|
|
195
|
-
*
|
|
196
|
-
* @returns {RegisteredPlugin[]} An array of RegisteredPlugin objects.
|
|
197
|
-
*/
|
|
198
149
|
getPlugins() {
|
|
199
150
|
return this.plugins.array();
|
|
200
151
|
}
|
|
201
|
-
/**
|
|
202
|
-
* Set the logger logLevel for the Matterbridge classes and call onChangeLoggerLevel() for each plugin.
|
|
203
|
-
*
|
|
204
|
-
* @param {LogLevel} logLevel The logger logLevel to set.
|
|
205
|
-
*/
|
|
206
152
|
async setLogLevel(logLevel) {
|
|
207
153
|
if (this.log)
|
|
208
154
|
this.log.logLevel = logLevel;
|
|
@@ -216,31 +162,19 @@ export class Matterbridge extends EventEmitter {
|
|
|
216
162
|
for (const plugin of this.plugins) {
|
|
217
163
|
if (!plugin.platform || !plugin.platform.log || !plugin.platform.config)
|
|
218
164
|
continue;
|
|
219
|
-
plugin.platform.log.logLevel = plugin.platform.config.debug === true ? "debug"
|
|
220
|
-
await plugin.platform.onChangeLoggerLevel(plugin.platform.config.debug === true ? "debug"
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
callbackLogLevel = "debug" /* LogLevel.DEBUG */;
|
|
165
|
+
plugin.platform.log.logLevel = plugin.platform.config.debug === true ? "debug" : this.log.logLevel;
|
|
166
|
+
await plugin.platform.onChangeLoggerLevel(plugin.platform.config.debug === true ? "debug" : this.log.logLevel);
|
|
167
|
+
}
|
|
168
|
+
let callbackLogLevel = "notice";
|
|
169
|
+
if (this.matterbridgeInformation.loggerLevel === "info" || this.matterbridgeInformation.matterLoggerLevel === MatterLogLevel.INFO)
|
|
170
|
+
callbackLogLevel = "info";
|
|
171
|
+
if (this.matterbridgeInformation.loggerLevel === "debug" || this.matterbridgeInformation.matterLoggerLevel === MatterLogLevel.DEBUG)
|
|
172
|
+
callbackLogLevel = "debug";
|
|
228
173
|
AnsiLogger.setGlobalCallback(this.frontend.wssSendMessage.bind(this.frontend), callbackLogLevel);
|
|
229
174
|
this.log.debug(`WebSocketServer logger global callback set to ${callbackLogLevel}`);
|
|
230
175
|
}
|
|
231
|
-
//* ************************************************************************************************************************************ */
|
|
232
|
-
// loadInstance() and cleanup() methods */
|
|
233
|
-
//* ************************************************************************************************************************************ */
|
|
234
|
-
/**
|
|
235
|
-
* Loads an instance of the Matterbridge class.
|
|
236
|
-
* If an instance already exists, return that instance.
|
|
237
|
-
*
|
|
238
|
-
* @param {boolean} initialize - Whether to initialize the Matterbridge instance after loading. Defaults to false.
|
|
239
|
-
* @returns {Matterbridge} A promise that resolves to the Matterbridge instance.
|
|
240
|
-
*/
|
|
241
176
|
static async loadInstance(initialize = false) {
|
|
242
177
|
if (!Matterbridge.instance) {
|
|
243
|
-
// eslint-disable-next-line no-console
|
|
244
178
|
if (hasParameter('debug'))
|
|
245
179
|
console.log(GREEN + 'Creating a new instance of Matterbridge.', initialize ? 'Initializing...' : 'Not initializing...', rs);
|
|
246
180
|
Matterbridge.instance = new Matterbridge();
|
|
@@ -249,17 +183,8 @@ export class Matterbridge extends EventEmitter {
|
|
|
249
183
|
}
|
|
250
184
|
return Matterbridge.instance;
|
|
251
185
|
}
|
|
252
|
-
/**
|
|
253
|
-
* Call cleanup() and dispose MdnsService.
|
|
254
|
-
*
|
|
255
|
-
* @param {number} [timeout] - The timeout duration to wait for the cleanup to complete in milliseconds. Default is 1000.
|
|
256
|
-
* @param {number} [pause] - The pause duration after the cleanup in milliseconds. Default is 250.
|
|
257
|
-
*
|
|
258
|
-
* @deprecated This method is deprecated and is ONLY used for jest tests.
|
|
259
|
-
*/
|
|
260
186
|
async destroyInstance(timeout = 1000, pause = 250) {
|
|
261
187
|
this.log.info(`Destroy instance...`);
|
|
262
|
-
// Save server nodes to close
|
|
263
188
|
const servers = [];
|
|
264
189
|
if (this.bridgeMode === 'bridge') {
|
|
265
190
|
if (this.serverNode)
|
|
@@ -277,105 +202,72 @@ export class Matterbridge extends EventEmitter {
|
|
|
277
202
|
servers.push(device.serverNode);
|
|
278
203
|
}
|
|
279
204
|
}
|
|
280
|
-
// Let any already‐queued microtasks run first
|
|
281
205
|
await Promise.resolve();
|
|
282
|
-
// Wait for the cleanup to finish
|
|
283
206
|
await wait(pause, 'destroyInstance start', true);
|
|
284
|
-
// Cleanup
|
|
285
207
|
await this.cleanup('destroying instance...', false, timeout);
|
|
286
|
-
// Close servers mdns service
|
|
287
208
|
this.log.info(`Dispose ${servers.length} MdnsService...`);
|
|
288
209
|
for (const server of servers) {
|
|
289
210
|
await server.env.get(MdnsService)[Symbol.asyncDispose]();
|
|
290
211
|
this.log.info(`Closed ${server.id} MdnsService`);
|
|
291
212
|
}
|
|
292
|
-
// Let any already‐queued microtasks run first
|
|
293
213
|
await Promise.resolve();
|
|
294
|
-
// Wait for the cleanup to finish
|
|
295
214
|
await wait(pause, 'destroyInstance stop', true);
|
|
296
215
|
}
|
|
297
|
-
/**
|
|
298
|
-
* Initializes the Matterbridge application.
|
|
299
|
-
*
|
|
300
|
-
* @remarks
|
|
301
|
-
* This method performs the necessary setup and initialization steps for the Matterbridge application.
|
|
302
|
-
* It displays the help information if the 'help' parameter is provided, sets up the logger, checks the
|
|
303
|
-
* node version, registers signal handlers, initializes storage, and parses the command line.
|
|
304
|
-
*
|
|
305
|
-
* @returns {Promise<void>} A Promise that resolves when the initialization is complete.
|
|
306
|
-
*/
|
|
307
216
|
async initialize() {
|
|
308
|
-
// Emit the initialize_started event
|
|
309
217
|
this.emit('initialize_started');
|
|
310
|
-
// Set the restart mode
|
|
311
218
|
if (hasParameter('service'))
|
|
312
219
|
this.restartMode = 'service';
|
|
313
220
|
if (hasParameter('docker'))
|
|
314
221
|
this.restartMode = 'docker';
|
|
315
|
-
// Set the matterbridge home directory
|
|
316
222
|
this.homeDirectory = getParameter('homedir') ?? os.homedir();
|
|
317
223
|
this.matterbridgeInformation.homeDirectory = this.homeDirectory;
|
|
318
224
|
await createDirectory(this.homeDirectory, 'Matterbridge Home Directory', this.log);
|
|
319
|
-
// Set the matterbridge directory
|
|
320
225
|
this.matterbridgeDirectory = path.join(this.homeDirectory, '.matterbridge');
|
|
321
226
|
this.matterbridgeInformation.matterbridgeDirectory = this.matterbridgeDirectory;
|
|
322
227
|
await createDirectory(this.matterbridgeDirectory, 'Matterbridge Directory', this.log);
|
|
323
228
|
await createDirectory(path.join(this.matterbridgeDirectory, 'certs'), 'Matterbridge Frontend Certificate Directory', this.log);
|
|
324
229
|
await createDirectory(path.join(this.matterbridgeDirectory, 'uploads'), 'Matterbridge Frontend Uploads Directory', this.log);
|
|
325
|
-
// Set the matterbridge plugin directory
|
|
326
230
|
this.matterbridgePluginDirectory = path.join(this.homeDirectory, 'Matterbridge');
|
|
327
231
|
this.matterbridgeInformation.matterbridgePluginDirectory = this.matterbridgePluginDirectory;
|
|
328
232
|
await createDirectory(this.matterbridgePluginDirectory, 'Matterbridge Plugin Directory', this.log);
|
|
329
|
-
// Set the matterbridge cert directory
|
|
330
233
|
this.matterbridgeCertDirectory = path.join(this.homeDirectory, '.mattercert');
|
|
331
234
|
this.matterbridgeInformation.matterbridgeCertDirectory = this.matterbridgeCertDirectory;
|
|
332
235
|
await createDirectory(this.matterbridgeCertDirectory, 'Matterbridge Matter Certificate Directory', this.log);
|
|
333
|
-
// Set the matterbridge root directory
|
|
334
236
|
const { fileURLToPath } = await import('node:url');
|
|
335
237
|
const currentFileDirectory = path.dirname(fileURLToPath(import.meta.url));
|
|
336
238
|
this.rootDirectory = path.resolve(currentFileDirectory, '../');
|
|
337
239
|
this.matterbridgeInformation.rootDirectory = this.rootDirectory;
|
|
338
|
-
// Setup the matter environment
|
|
339
240
|
this.environment.vars.set('log.level', MatterLogLevel.INFO);
|
|
340
241
|
this.environment.vars.set('log.format', MatterLogFormat.ANSI);
|
|
341
242
|
this.environment.vars.set('path.root', path.join(this.matterbridgeDirectory, this.matterStorageName));
|
|
342
243
|
this.environment.vars.set('runtime.signals', false);
|
|
343
244
|
this.environment.vars.set('runtime.exitcode', false);
|
|
344
|
-
// Register process handlers
|
|
345
245
|
this.registerProcessHandlers();
|
|
346
|
-
// Initialize nodeStorage and nodeContext
|
|
347
246
|
try {
|
|
348
247
|
this.log.debug(`Creating node storage manager: ${CYAN}${this.nodeStorageName}${db}`);
|
|
349
248
|
this.nodeStorage = new NodeStorageManager({ dir: path.join(this.matterbridgeDirectory, this.nodeStorageName), writeQueue: false, expiredInterval: undefined, logging: false });
|
|
350
249
|
this.log.debug('Creating node storage context for matterbridge');
|
|
351
250
|
this.nodeContext = await this.nodeStorage.createStorage('matterbridge');
|
|
352
|
-
// TODO: Remove this code when node-persist-manager is updated
|
|
353
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
354
251
|
const keys = (await this.nodeStorage?.storage.keys());
|
|
355
252
|
for (const key of keys) {
|
|
356
253
|
this.log.debug(`Checking node storage manager key: ${CYAN}${key}${db}`);
|
|
357
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
358
254
|
await this.nodeStorage?.storage.get(key);
|
|
359
255
|
}
|
|
360
256
|
const storages = await this.nodeStorage.getStorageNames();
|
|
361
257
|
for (const storage of storages) {
|
|
362
258
|
this.log.debug(`Checking storage: ${CYAN}${storage}${db}`);
|
|
363
259
|
const nodeContext = await this.nodeStorage?.createStorage(storage);
|
|
364
|
-
// TODO: Remove this code when node-persist-manager is updated
|
|
365
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
366
260
|
const keys = (await nodeContext?.storage.keys());
|
|
367
261
|
keys.forEach(async (key) => {
|
|
368
262
|
this.log.debug(`Checking key: ${CYAN}${storage}:${key}${db}`);
|
|
369
263
|
await nodeContext?.get(key);
|
|
370
264
|
});
|
|
371
265
|
}
|
|
372
|
-
// Creating a backup of the node storage since it is not corrupted
|
|
373
266
|
this.log.debug('Creating node storage backup...');
|
|
374
267
|
await copyDirectory(path.join(this.matterbridgeDirectory, this.nodeStorageName), path.join(this.matterbridgeDirectory, this.nodeStorageName + '.backup'));
|
|
375
268
|
this.log.debug('Created node storage backup');
|
|
376
269
|
}
|
|
377
270
|
catch (error) {
|
|
378
|
-
// Restoring the backup of the node storage since it is corrupted
|
|
379
271
|
this.log.error(`Error creating node storage manager and context: ${error instanceof Error ? error.message : error}`);
|
|
380
272
|
if (hasParameter('norestore')) {
|
|
381
273
|
this.log.fatal(`The matterbridge storage is corrupted. Found -norestore parameter: exiting...`);
|
|
@@ -389,19 +281,14 @@ export class Matterbridge extends EventEmitter {
|
|
|
389
281
|
if (!this.nodeStorage || !this.nodeContext) {
|
|
390
282
|
throw new Error('Fatal error creating node storage manager and context for matterbridge');
|
|
391
283
|
}
|
|
392
|
-
// Set the first port to use for the commissioning server (will be incremented in childbridge mode)
|
|
393
284
|
this.port = getIntParameter('port') ?? (await this.nodeContext.get('matterport', 5540)) ?? 5540;
|
|
394
|
-
// Set the first passcode to use for the commissioning server (will be incremented in childbridge mode)
|
|
395
285
|
this.passcode = getIntParameter('passcode') ?? (await this.nodeContext.get('matterpasscode')) ?? PaseClient.generateRandomPasscode(this.environment.get(Crypto));
|
|
396
|
-
// Set the first discriminator to use for the commissioning server (will be incremented in childbridge mode)
|
|
397
286
|
this.discriminator = getIntParameter('discriminator') ?? (await this.nodeContext.get('matterdiscriminator')) ?? PaseClient.generateRandomDiscriminator(this.environment.get(Crypto));
|
|
398
|
-
// Certificate management
|
|
399
287
|
const pairingFilePath = path.join(this.matterbridgeCertDirectory, 'pairing.json');
|
|
400
288
|
try {
|
|
401
289
|
await fs.access(pairingFilePath, fs.constants.R_OK);
|
|
402
290
|
const pairingFileContent = await fs.readFile(pairingFilePath, 'utf8');
|
|
403
291
|
const pairingFileJson = JSON.parse(pairingFileContent);
|
|
404
|
-
// Set the vendorId, vendorName, productId, productName, deviceType, serialNumber, uniqueId if they are present in the pairing file
|
|
405
292
|
if (isValidNumber(pairingFileJson.vendorId)) {
|
|
406
293
|
this.aggregatorVendorId = VendorId(pairingFileJson.vendorId);
|
|
407
294
|
this.log.info(`Pairing file ${CYAN}${pairingFilePath}${nf} found. Using vendorId ${CYAN}${this.aggregatorVendorId}${nf} from pairing file.`);
|
|
@@ -430,13 +317,11 @@ export class Matterbridge extends EventEmitter {
|
|
|
430
317
|
this.aggregatorUniqueId = pairingFileJson.uniqueId;
|
|
431
318
|
this.log.info(`Pairing file ${CYAN}${pairingFilePath}${nf} found. Using uniqueId ${CYAN}${this.aggregatorUniqueId}${nf} from pairing file.`);
|
|
432
319
|
}
|
|
433
|
-
// Override the passcode and discriminator if they are present in the pairing file
|
|
434
320
|
if (isValidNumber(pairingFileJson.passcode) && isValidNumber(pairingFileJson.discriminator)) {
|
|
435
321
|
this.passcode = pairingFileJson.passcode;
|
|
436
322
|
this.discriminator = pairingFileJson.discriminator;
|
|
437
323
|
this.log.info(`Pairing file ${CYAN}${pairingFilePath}${nf} found. Using passcode ${CYAN}${this.passcode}${nf} and discriminator ${CYAN}${this.discriminator}${nf} from pairing file.`);
|
|
438
324
|
}
|
|
439
|
-
// Set the certification for matter.js if it is present in the pairing file
|
|
440
325
|
if (pairingFileJson.privateKey && pairingFileJson.certificate && pairingFileJson.intermediateCertificate && pairingFileJson.declaration) {
|
|
441
326
|
const { hexToBuffer } = await import('./utils/hex.js');
|
|
442
327
|
this.certification = {
|
|
@@ -451,44 +336,41 @@ export class Matterbridge extends EventEmitter {
|
|
|
451
336
|
catch (error) {
|
|
452
337
|
this.log.debug(`Pairing file ${CYAN}${pairingFilePath}${db} not found: ${error instanceof Error ? error.message : error}`);
|
|
453
338
|
}
|
|
454
|
-
// Store the passcode, discriminator and port in the node context
|
|
455
339
|
await this.nodeContext.set('matterport', this.port);
|
|
456
340
|
await this.nodeContext.set('matterpasscode', this.passcode);
|
|
457
341
|
await this.nodeContext.set('matterdiscriminator', this.discriminator);
|
|
458
342
|
this.log.debug(`Initializing server node for Matterbridge on port ${this.port} with passcode ${this.passcode} and discriminator ${this.discriminator}`);
|
|
459
|
-
// Set matterbridge logger level (context: matterbridgeLogLevel)
|
|
460
343
|
if (hasParameter('logger')) {
|
|
461
344
|
const level = getParameter('logger');
|
|
462
345
|
if (level === 'debug') {
|
|
463
|
-
this.log.logLevel = "debug"
|
|
346
|
+
this.log.logLevel = "debug";
|
|
464
347
|
}
|
|
465
348
|
else if (level === 'info') {
|
|
466
|
-
this.log.logLevel = "info"
|
|
349
|
+
this.log.logLevel = "info";
|
|
467
350
|
}
|
|
468
351
|
else if (level === 'notice') {
|
|
469
|
-
this.log.logLevel = "notice"
|
|
352
|
+
this.log.logLevel = "notice";
|
|
470
353
|
}
|
|
471
354
|
else if (level === 'warn') {
|
|
472
|
-
this.log.logLevel = "warn"
|
|
355
|
+
this.log.logLevel = "warn";
|
|
473
356
|
}
|
|
474
357
|
else if (level === 'error') {
|
|
475
|
-
this.log.logLevel = "error"
|
|
358
|
+
this.log.logLevel = "error";
|
|
476
359
|
}
|
|
477
360
|
else if (level === 'fatal') {
|
|
478
|
-
this.log.logLevel = "fatal"
|
|
361
|
+
this.log.logLevel = "fatal";
|
|
479
362
|
}
|
|
480
363
|
else {
|
|
481
364
|
this.log.warn(`Invalid matterbridge logger level: ${level}. Using default level "info".`);
|
|
482
|
-
this.log.logLevel = "info"
|
|
365
|
+
this.log.logLevel = "info";
|
|
483
366
|
}
|
|
484
367
|
}
|
|
485
368
|
else {
|
|
486
|
-
this.log.logLevel = await this.nodeContext.get('matterbridgeLogLevel', this.matterbridgeInformation.shellyBoard ? "notice"
|
|
369
|
+
this.log.logLevel = await this.nodeContext.get('matterbridgeLogLevel', this.matterbridgeInformation.shellyBoard ? "notice" : "info");
|
|
487
370
|
}
|
|
488
371
|
this.frontend.logLevel = this.log.logLevel;
|
|
489
372
|
MatterbridgeEndpoint.logLevel = this.log.logLevel;
|
|
490
373
|
this.matterbridgeInformation.loggerLevel = this.log.logLevel;
|
|
491
|
-
// Create the file logger for matterbridge (context: matterbridgeFileLog)
|
|
492
374
|
if (hasParameter('filelogger') || (await this.nodeContext.get('matterbridgeFileLog', false))) {
|
|
493
375
|
AnsiLogger.setGlobalLogfile(path.join(this.matterbridgeDirectory, this.matterbridgeLoggerFile), this.log.logLevel, true);
|
|
494
376
|
this.matterbridgeInformation.fileLogger = true;
|
|
@@ -497,7 +379,6 @@ export class Matterbridge extends EventEmitter {
|
|
|
497
379
|
this.log.debug(`Matterbridge logLevel: ${this.log.logLevel} fileLoger: ${this.matterbridgeInformation.fileLogger}.`);
|
|
498
380
|
if (this.profile !== undefined)
|
|
499
381
|
this.log.debug(`Matterbridge profile: ${this.profile}.`);
|
|
500
|
-
// Set matter.js logger level, format and logger (context: matterLogLevel)
|
|
501
382
|
if (hasParameter('matterlogger')) {
|
|
502
383
|
const level = getParameter('matterlogger');
|
|
503
384
|
if (level === 'debug') {
|
|
@@ -528,9 +409,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
528
409
|
}
|
|
529
410
|
Logger.format = MatterLogFormat.ANSI;
|
|
530
411
|
Logger.setLogger('default', this.createMatterLogger());
|
|
531
|
-
// Logger.destinations.default.write = this.createMatterLogger();
|
|
532
412
|
this.matterbridgeInformation.matterLoggerLevel = Logger.level;
|
|
533
|
-
// Create the file logger for matter.js (context: matterFileLog)
|
|
534
413
|
if (hasParameter('matterfilelogger') || (await this.nodeContext.get('matterFileLog', false))) {
|
|
535
414
|
this.matterbridgeInformation.matterFileLogger = true;
|
|
536
415
|
Logger.addLogger('matterfilelogger', await this.createMatterFileLogger(path.join(this.matterbridgeDirectory, this.matterLoggerFile), true), {
|
|
@@ -539,9 +418,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
539
418
|
});
|
|
540
419
|
}
|
|
541
420
|
this.log.debug(`Matter logLevel: ${Logger.level} fileLoger: ${this.matterbridgeInformation.matterFileLogger}.`);
|
|
542
|
-
// Log network interfaces
|
|
543
421
|
const networkInterfaces = os.networkInterfaces();
|
|
544
|
-
// console.log(`Network interfaces:`, networkInterfaces);
|
|
545
422
|
const availableAddresses = Object.entries(networkInterfaces);
|
|
546
423
|
const availableInterfaces = Object.keys(networkInterfaces);
|
|
547
424
|
for (const [ifaceName, ifaces] of availableAddresses) {
|
|
@@ -553,7 +430,6 @@ export class Matterbridge extends EventEmitter {
|
|
|
553
430
|
});
|
|
554
431
|
}
|
|
555
432
|
}
|
|
556
|
-
// Set the interface to use for matter server node mdnsInterface
|
|
557
433
|
if (hasParameter('mdnsinterface')) {
|
|
558
434
|
this.mdnsInterface = getParameter('mdnsinterface');
|
|
559
435
|
}
|
|
@@ -562,7 +438,6 @@ export class Matterbridge extends EventEmitter {
|
|
|
562
438
|
if (this.mdnsInterface === '')
|
|
563
439
|
this.mdnsInterface = undefined;
|
|
564
440
|
}
|
|
565
|
-
// Validate mdnsInterface
|
|
566
441
|
if (this.mdnsInterface) {
|
|
567
442
|
if (!availableInterfaces.includes(this.mdnsInterface)) {
|
|
568
443
|
this.log.error(`Invalid mdnsinterface: ${this.mdnsInterface}. Available interfaces are: ${availableInterfaces.join(', ')}. Using all available interfaces.`);
|
|
@@ -575,7 +450,6 @@ export class Matterbridge extends EventEmitter {
|
|
|
575
450
|
}
|
|
576
451
|
if (this.mdnsInterface)
|
|
577
452
|
this.environment.vars.set('mdns.networkInterface', this.mdnsInterface);
|
|
578
|
-
// Set the listeningAddressIpv4 for the matter commissioning server
|
|
579
453
|
if (hasParameter('ipv4address')) {
|
|
580
454
|
this.ipv4address = getParameter('ipv4address');
|
|
581
455
|
}
|
|
@@ -584,7 +458,6 @@ export class Matterbridge extends EventEmitter {
|
|
|
584
458
|
if (this.ipv4address === '')
|
|
585
459
|
this.ipv4address = undefined;
|
|
586
460
|
}
|
|
587
|
-
// Validate ipv4address
|
|
588
461
|
if (this.ipv4address) {
|
|
589
462
|
let isValid = false;
|
|
590
463
|
for (const [ifaceName, ifaces] of availableAddresses) {
|
|
@@ -600,7 +473,6 @@ export class Matterbridge extends EventEmitter {
|
|
|
600
473
|
await this.nodeContext.remove('matteripv4address');
|
|
601
474
|
}
|
|
602
475
|
}
|
|
603
|
-
// Set the listeningAddressIpv6 for the matter commissioning server
|
|
604
476
|
if (hasParameter('ipv6address')) {
|
|
605
477
|
this.ipv6address = getParameter('ipv6address');
|
|
606
478
|
}
|
|
@@ -609,7 +481,6 @@ export class Matterbridge extends EventEmitter {
|
|
|
609
481
|
if (this.ipv6address === '')
|
|
610
482
|
this.ipv6address = undefined;
|
|
611
483
|
}
|
|
612
|
-
// Validate ipv6address
|
|
613
484
|
if (this.ipv6address) {
|
|
614
485
|
let isValid = false;
|
|
615
486
|
for (const [ifaceName, ifaces] of availableAddresses) {
|
|
@@ -618,7 +489,6 @@ export class Matterbridge extends EventEmitter {
|
|
|
618
489
|
isValid = true;
|
|
619
490
|
break;
|
|
620
491
|
}
|
|
621
|
-
/* istanbul ignore next */
|
|
622
492
|
if (ifaces && ifaces.find((iface) => iface.scopeid && iface.scopeid > 0 && iface.address + '%' + (process.platform === 'win32' ? iface.scopeid : ifaceName) === this.ipv6address)) {
|
|
623
493
|
this.log.info(`Using ipv6address ${CYAN}${this.ipv6address}${nf} on interface ${CYAN}${ifaceName}${nf} for the Matter server node.`);
|
|
624
494
|
isValid = true;
|
|
@@ -631,7 +501,6 @@ export class Matterbridge extends EventEmitter {
|
|
|
631
501
|
await this.nodeContext.remove('matteripv6address');
|
|
632
502
|
}
|
|
633
503
|
}
|
|
634
|
-
// Initialize the virtual mode
|
|
635
504
|
if (hasParameter('novirtual')) {
|
|
636
505
|
this.matterbridgeInformation.virtualMode = 'disabled';
|
|
637
506
|
await this.nodeContext.set('virtualmode', 'disabled');
|
|
@@ -640,17 +509,12 @@ export class Matterbridge extends EventEmitter {
|
|
|
640
509
|
this.matterbridgeInformation.virtualMode = (await this.nodeContext.get('virtualmode', 'outlet'));
|
|
641
510
|
}
|
|
642
511
|
this.log.debug(`Virtual mode ${this.matterbridgeInformation.virtualMode}.`);
|
|
643
|
-
// Initialize PluginManager
|
|
644
512
|
this.plugins.logLevel = this.log.logLevel;
|
|
645
513
|
await this.plugins.loadFromStorage();
|
|
646
|
-
// Initialize DeviceManager
|
|
647
514
|
this.devices.logLevel = this.log.logLevel;
|
|
648
|
-
// Get the plugins from node storage and create the plugins node storage contexts
|
|
649
515
|
for (const plugin of this.plugins) {
|
|
650
516
|
const packageJson = await this.plugins.parse(plugin);
|
|
651
517
|
if (packageJson === null && !hasParameter('add') && !hasParameter('remove') && !hasParameter('enable') && !hasParameter('disable') && !hasParameter('reset') && !hasParameter('factoryreset')) {
|
|
652
|
-
// Try to reinstall the plugin from npm (for Docker pull and external plugins)
|
|
653
|
-
// We don't do this when the add and other parameters are set because we shut down the process after adding the plugin
|
|
654
518
|
this.log.info(`Error parsing plugin ${plg}${plugin.name}${nf}. Trying to reinstall it from npm.`);
|
|
655
519
|
try {
|
|
656
520
|
const { spawnCommand } = await import('./utils/spawn.js');
|
|
@@ -673,7 +537,6 @@ export class Matterbridge extends EventEmitter {
|
|
|
673
537
|
await plugin.nodeContext.set('description', plugin.description);
|
|
674
538
|
await plugin.nodeContext.set('author', plugin.author);
|
|
675
539
|
}
|
|
676
|
-
// Log system info and create .matterbridge directory
|
|
677
540
|
await this.logNodeAndSystemInfo();
|
|
678
541
|
this.log.notice(`Matterbridge version ${this.matterbridgeVersion} ` +
|
|
679
542
|
`${hasParameter('bridge') || (!hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'bridge') ? 'mode bridge ' : ''}` +
|
|
@@ -681,7 +544,6 @@ export class Matterbridge extends EventEmitter {
|
|
|
681
544
|
`${hasParameter('controller') ? 'mode controller ' : ''}` +
|
|
682
545
|
`${this.restartMode !== '' ? 'restart mode ' + this.restartMode + ' ' : ''}` +
|
|
683
546
|
`running on ${this.systemInformation.osType} (v.${this.systemInformation.osRelease}) platform ${this.systemInformation.osPlatform} arch ${this.systemInformation.osArch}`);
|
|
684
|
-
// Check node version and throw error
|
|
685
547
|
const minNodeVersion = 18;
|
|
686
548
|
const nodeVersion = process.versions.node;
|
|
687
549
|
const versionMajor = parseInt(nodeVersion.split('.')[0]);
|
|
@@ -689,18 +551,10 @@ export class Matterbridge extends EventEmitter {
|
|
|
689
551
|
this.log.error(`Node version ${versionMajor} is not supported. Please upgrade to ${minNodeVersion} or above.`);
|
|
690
552
|
throw new Error(`Node version ${versionMajor} is not supported. Please upgrade to ${minNodeVersion} or above.`);
|
|
691
553
|
}
|
|
692
|
-
// Parse command line
|
|
693
554
|
await this.parseCommandLine();
|
|
694
|
-
// Emit the initialize_completed event
|
|
695
555
|
this.emit('initialize_completed');
|
|
696
556
|
this.initialized = true;
|
|
697
557
|
}
|
|
698
|
-
/**
|
|
699
|
-
* Parses the command line arguments and performs the corresponding actions.
|
|
700
|
-
*
|
|
701
|
-
* @private
|
|
702
|
-
* @returns {Promise<void>} A promise that resolves when the command line arguments have been processed, or the process exits.
|
|
703
|
-
*/
|
|
704
558
|
async parseCommandLine() {
|
|
705
559
|
if (hasParameter('help')) {
|
|
706
560
|
this.log.info(`\nUsage: matterbridge [options]\n
|
|
@@ -762,19 +616,6 @@ export class Matterbridge extends EventEmitter {
|
|
|
762
616
|
}
|
|
763
617
|
index++;
|
|
764
618
|
}
|
|
765
|
-
/*
|
|
766
|
-
const serializedRegisteredDevices = await this.nodeContext?.get<SerializedMatterbridgeEndpoint[]>('devices', []);
|
|
767
|
-
this.log.info(`│ Registered devices (${serializedRegisteredDevices?.length})`);
|
|
768
|
-
serializedRegisteredDevices?.forEach((device, index) => {
|
|
769
|
-
if (index !== serializedRegisteredDevices.length - 1) {
|
|
770
|
-
this.log.info(`├─┬─ plugin ${plg}${device.pluginName}${nf} device: ${dev}${device.deviceName}${nf} uniqueId: ${YELLOW}${device.uniqueId}${nf}`);
|
|
771
|
-
this.log.info(`│ └─ endpoint ${RED}${device.endpoint}${nf} ${typ}${device.endpointName}${nf} ${debugStringify(device.clusterServersId)}`);
|
|
772
|
-
} else {
|
|
773
|
-
this.log.info(`└─┬─ plugin ${plg}${device.pluginName}${nf} device: ${dev}${device.deviceName}${nf} uniqueId: ${YELLOW}${device.uniqueId}${nf}`);
|
|
774
|
-
this.log.info(` └─ endpoint ${RED}${device.endpoint}${nf} ${typ}${device.endpointName}${nf} ${debugStringify(device.clusterServersId)}`);
|
|
775
|
-
}
|
|
776
|
-
});
|
|
777
|
-
*/
|
|
778
619
|
this.shutdown = true;
|
|
779
620
|
return;
|
|
780
621
|
}
|
|
@@ -824,7 +665,6 @@ export class Matterbridge extends EventEmitter {
|
|
|
824
665
|
this.shutdown = true;
|
|
825
666
|
return;
|
|
826
667
|
}
|
|
827
|
-
// Start the matter storage and create the matterbridge context
|
|
828
668
|
try {
|
|
829
669
|
await this.startMatterStorage();
|
|
830
670
|
if (this.aggregatorSerialNumber && this.aggregatorUniqueId && this.matterStorageService) {
|
|
@@ -841,21 +681,18 @@ export class Matterbridge extends EventEmitter {
|
|
|
841
681
|
this.log.fatal(`Fatal error creating matter storage: ${error instanceof Error ? error.message : error}`);
|
|
842
682
|
throw new Error(`Fatal error creating matter storage: ${error instanceof Error ? error.message : error}`);
|
|
843
683
|
}
|
|
844
|
-
// Clear the matterbridge context if the reset parameter is set
|
|
845
684
|
if (hasParameter('reset') && getParameter('reset') === undefined) {
|
|
846
685
|
this.initialized = true;
|
|
847
686
|
await this.shutdownProcessAndReset();
|
|
848
687
|
this.shutdown = true;
|
|
849
688
|
return;
|
|
850
689
|
}
|
|
851
|
-
// Clear matterbridge plugin context if the reset parameter is set
|
|
852
690
|
if (hasParameter('reset') && getParameter('reset') !== undefined) {
|
|
853
691
|
this.log.debug(`Reset plugin ${getParameter('reset')}`);
|
|
854
692
|
const plugin = this.plugins.get(getParameter('reset'));
|
|
855
693
|
if (plugin) {
|
|
856
694
|
const matterStorageManager = await this.matterStorageService?.open(plugin.name);
|
|
857
695
|
if (!matterStorageManager) {
|
|
858
|
-
/* istanbul ignore next */
|
|
859
696
|
this.log.error(`Plugin ${plg}${plugin.name}${er} storageManager not found`);
|
|
860
697
|
}
|
|
861
698
|
else {
|
|
@@ -874,45 +711,37 @@ export class Matterbridge extends EventEmitter {
|
|
|
874
711
|
this.shutdown = true;
|
|
875
712
|
return;
|
|
876
713
|
}
|
|
877
|
-
// Initialize frontend
|
|
878
714
|
if (getIntParameter('frontend') !== 0 || getIntParameter('frontend') === undefined)
|
|
879
715
|
await this.frontend.start(getIntParameter('frontend'));
|
|
880
|
-
// Check in 30 seconds the latest and dev versions of matterbridge and the plugins
|
|
881
716
|
clearTimeout(this.checkUpdateTimeout);
|
|
882
717
|
this.checkUpdateTimeout = setTimeout(async () => {
|
|
883
718
|
const { checkUpdates } = await import('./update.js');
|
|
884
719
|
checkUpdates(this);
|
|
885
720
|
}, 30 * 1000).unref();
|
|
886
|
-
// Check each 12 hours the latest and dev versions of matterbridge and the plugins
|
|
887
721
|
clearInterval(this.checkUpdateInterval);
|
|
888
722
|
this.checkUpdateInterval = setInterval(async () => {
|
|
889
723
|
const { checkUpdates } = await import('./update.js');
|
|
890
724
|
checkUpdates(this);
|
|
891
725
|
}, 12 * 60 * 60 * 1000).unref();
|
|
892
|
-
// Start the matterbridge in mode test
|
|
893
726
|
if (hasParameter('test')) {
|
|
894
727
|
this.bridgeMode = 'bridge';
|
|
895
728
|
return;
|
|
896
729
|
}
|
|
897
|
-
// Start the matterbridge in mode controller
|
|
898
730
|
if (hasParameter('controller')) {
|
|
899
731
|
this.bridgeMode = 'controller';
|
|
900
732
|
await this.startController();
|
|
901
733
|
return;
|
|
902
734
|
}
|
|
903
|
-
// Check if the bridge mode is set and start matterbridge in bridge mode if not set
|
|
904
735
|
if (!hasParameter('bridge') && !hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === '') {
|
|
905
736
|
this.log.info('Setting default matterbridge start mode to bridge');
|
|
906
737
|
await this.nodeContext?.set('bridgeMode', 'bridge');
|
|
907
738
|
}
|
|
908
|
-
// Start matterbridge in bridge mode
|
|
909
739
|
if (hasParameter('bridge') || (!hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'bridge')) {
|
|
910
740
|
this.bridgeMode = 'bridge';
|
|
911
741
|
this.log.debug(`Starting matterbridge in mode ${this.bridgeMode}`);
|
|
912
742
|
await this.startBridge();
|
|
913
743
|
return;
|
|
914
744
|
}
|
|
915
|
-
// Start matterbridge in childbridge mode
|
|
916
745
|
if (hasParameter('childbridge') || (!hasParameter('bridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'childbridge')) {
|
|
917
746
|
this.bridgeMode = 'childbridge';
|
|
918
747
|
this.log.debug(`Starting matterbridge in mode ${this.bridgeMode}`);
|
|
@@ -920,20 +749,10 @@ export class Matterbridge extends EventEmitter {
|
|
|
920
749
|
return;
|
|
921
750
|
}
|
|
922
751
|
}
|
|
923
|
-
/**
|
|
924
|
-
* Asynchronously loads and starts the registered plugins.
|
|
925
|
-
*
|
|
926
|
-
* This method is responsible for initializing and starting all enabled plugins.
|
|
927
|
-
* It ensures that each plugin is properly loaded and started before the bridge starts.
|
|
928
|
-
*
|
|
929
|
-
* @returns {Promise<void>} A promise that resolves when all plugins have been loaded and started.
|
|
930
|
-
*/
|
|
931
752
|
async startPlugins() {
|
|
932
|
-
// Check, load and start the plugins
|
|
933
753
|
for (const plugin of this.plugins) {
|
|
934
754
|
plugin.configJson = await this.plugins.loadConfig(plugin);
|
|
935
755
|
plugin.schemaJson = await this.plugins.loadSchema(plugin);
|
|
936
|
-
// Check if the plugin is available
|
|
937
756
|
if (!(await this.plugins.resolve(plugin.path))) {
|
|
938
757
|
this.log.error(`Plugin ${plg}${plugin.name}${er} not found or not validated. Disabling it.`);
|
|
939
758
|
plugin.enabled = false;
|
|
@@ -951,14 +770,10 @@ export class Matterbridge extends EventEmitter {
|
|
|
951
770
|
plugin.configured = false;
|
|
952
771
|
plugin.registeredDevices = undefined;
|
|
953
772
|
plugin.addedDevices = undefined;
|
|
954
|
-
this.plugins.load(plugin, true, 'Matterbridge is starting');
|
|
773
|
+
this.plugins.load(plugin, true, 'Matterbridge is starting');
|
|
955
774
|
}
|
|
956
775
|
this.frontend.wssSendRefreshRequired('plugins');
|
|
957
776
|
}
|
|
958
|
-
/**
|
|
959
|
-
* Registers the process handlers for uncaughtException, unhandledRejection, SIGINT and SIGTERM.
|
|
960
|
-
* When either of these signals are received, the cleanup method is called with an appropriate message.
|
|
961
|
-
*/
|
|
962
777
|
registerProcessHandlers() {
|
|
963
778
|
this.log.debug(`Registering uncaughtException and unhandledRejection handlers...`);
|
|
964
779
|
process.removeAllListeners('uncaughtException');
|
|
@@ -985,9 +800,6 @@ export class Matterbridge extends EventEmitter {
|
|
|
985
800
|
};
|
|
986
801
|
process.on('SIGTERM', this.sigtermHandler);
|
|
987
802
|
}
|
|
988
|
-
/**
|
|
989
|
-
* Deregisters the process uncaughtException, unhandledRejection, SIGINT and SIGTERM signal handlers.
|
|
990
|
-
*/
|
|
991
803
|
deregisterProcessHandlers() {
|
|
992
804
|
this.log.debug(`Deregistering uncaughtException and unhandledRejection handlers...`);
|
|
993
805
|
if (this.exceptionHandler)
|
|
@@ -1004,17 +816,12 @@ export class Matterbridge extends EventEmitter {
|
|
|
1004
816
|
process.off('SIGTERM', this.sigtermHandler);
|
|
1005
817
|
this.sigtermHandler = undefined;
|
|
1006
818
|
}
|
|
1007
|
-
/**
|
|
1008
|
-
* Logs the node and system information.
|
|
1009
|
-
*/
|
|
1010
819
|
async logNodeAndSystemInfo() {
|
|
1011
|
-
// IP address information
|
|
1012
820
|
const networkInterfaces = os.networkInterfaces();
|
|
1013
821
|
this.systemInformation.interfaceName = '';
|
|
1014
822
|
this.systemInformation.ipv4Address = '';
|
|
1015
823
|
this.systemInformation.ipv6Address = '';
|
|
1016
824
|
for (const [interfaceName, interfaceDetails] of Object.entries(networkInterfaces)) {
|
|
1017
|
-
// this.log.debug(`Checking interface: '${interfaceName}' for '${this.mdnsInterface}'`);
|
|
1018
825
|
if (this.mdnsInterface && interfaceName !== this.mdnsInterface)
|
|
1019
826
|
continue;
|
|
1020
827
|
if (!interfaceDetails) {
|
|
@@ -1040,22 +847,19 @@ export class Matterbridge extends EventEmitter {
|
|
|
1040
847
|
break;
|
|
1041
848
|
}
|
|
1042
849
|
}
|
|
1043
|
-
// Node information
|
|
1044
850
|
this.systemInformation.nodeVersion = process.versions.node;
|
|
1045
851
|
const versionMajor = parseInt(this.systemInformation.nodeVersion.split('.')[0]);
|
|
1046
852
|
const versionMinor = parseInt(this.systemInformation.nodeVersion.split('.')[1]);
|
|
1047
853
|
const versionPatch = parseInt(this.systemInformation.nodeVersion.split('.')[2]);
|
|
1048
|
-
// Host system information
|
|
1049
854
|
this.systemInformation.hostname = os.hostname();
|
|
1050
855
|
this.systemInformation.user = os.userInfo().username;
|
|
1051
|
-
this.systemInformation.osType = os.type();
|
|
1052
|
-
this.systemInformation.osRelease = os.release();
|
|
1053
|
-
this.systemInformation.osPlatform = os.platform();
|
|
1054
|
-
this.systemInformation.osArch = os.arch();
|
|
1055
|
-
this.systemInformation.totalMemory = (os.totalmem() / 1024 / 1024 / 1024).toFixed(2) + ' GB';
|
|
1056
|
-
this.systemInformation.freeMemory = (os.freemem() / 1024 / 1024 / 1024).toFixed(2) + ' GB';
|
|
1057
|
-
this.systemInformation.systemUptime = (os.uptime() / 60 / 60).toFixed(2) + ' hours';
|
|
1058
|
-
// Log the system information
|
|
856
|
+
this.systemInformation.osType = os.type();
|
|
857
|
+
this.systemInformation.osRelease = os.release();
|
|
858
|
+
this.systemInformation.osPlatform = os.platform();
|
|
859
|
+
this.systemInformation.osArch = os.arch();
|
|
860
|
+
this.systemInformation.totalMemory = (os.totalmem() / 1024 / 1024 / 1024).toFixed(2) + ' GB';
|
|
861
|
+
this.systemInformation.freeMemory = (os.freemem() / 1024 / 1024 / 1024).toFixed(2) + ' GB';
|
|
862
|
+
this.systemInformation.systemUptime = (os.uptime() / 60 / 60).toFixed(2) + ' hours';
|
|
1059
863
|
this.log.debug('Host System Information:');
|
|
1060
864
|
this.log.debug(`- Hostname: ${this.systemInformation.hostname}`);
|
|
1061
865
|
this.log.debug(`- User: ${this.systemInformation.user}`);
|
|
@@ -1071,17 +875,14 @@ export class Matterbridge extends EventEmitter {
|
|
|
1071
875
|
this.log.debug(`- Total Memory: ${this.systemInformation.totalMemory}`);
|
|
1072
876
|
this.log.debug(`- Free Memory: ${this.systemInformation.freeMemory}`);
|
|
1073
877
|
this.log.debug(`- System Uptime: ${this.systemInformation.systemUptime}`);
|
|
1074
|
-
// Log directories
|
|
1075
878
|
this.log.debug(`Root Directory: ${this.rootDirectory}`);
|
|
1076
879
|
this.log.debug(`Home Directory: ${this.homeDirectory}`);
|
|
1077
880
|
this.log.debug(`Matterbridge Directory: ${this.matterbridgeDirectory}`);
|
|
1078
881
|
this.log.debug(`Matterbridge Plugin Directory: ${this.matterbridgePluginDirectory}`);
|
|
1079
882
|
this.log.debug(`Matterbridge Matter Certificate Directory: ${this.matterbridgeCertDirectory}`);
|
|
1080
|
-
// Global node_modules directory
|
|
1081
883
|
if (this.nodeContext)
|
|
1082
884
|
this.globalModulesDirectory = this.matterbridgeInformation.globalModulesDirectory = await this.nodeContext.get('globalModulesDirectory', '');
|
|
1083
885
|
if (this.globalModulesDirectory === '') {
|
|
1084
|
-
// First run of Matterbridge so the node storage is empty
|
|
1085
886
|
this.log.debug(`Getting global node_modules directory...`);
|
|
1086
887
|
try {
|
|
1087
888
|
const { getGlobalNodeModules } = await import('./utils/network.js');
|
|
@@ -1094,7 +895,6 @@ export class Matterbridge extends EventEmitter {
|
|
|
1094
895
|
}
|
|
1095
896
|
}
|
|
1096
897
|
else {
|
|
1097
|
-
// The global node_modules directory is already set in the node storage and we check if it is still valid
|
|
1098
898
|
this.log.debug(`Checking global node_modules directory: ${this.globalModulesDirectory}`);
|
|
1099
899
|
try {
|
|
1100
900
|
const { getGlobalNodeModules } = await import('./utils/network.js');
|
|
@@ -1106,68 +906,50 @@ export class Matterbridge extends EventEmitter {
|
|
|
1106
906
|
this.log.error(`Error checking global node_modules directory: ${error}`);
|
|
1107
907
|
}
|
|
1108
908
|
}
|
|
1109
|
-
// Matterbridge version
|
|
1110
909
|
const packageJson = JSON.parse(await fs.readFile(path.join(this.rootDirectory, 'package.json'), 'utf-8'));
|
|
1111
910
|
this.matterbridgeVersion = this.matterbridgeLatestVersion = this.matterbridgeDevVersion = packageJson.version;
|
|
1112
911
|
this.matterbridgeInformation.matterbridgeVersion = this.matterbridgeInformation.matterbridgeLatestVersion = this.matterbridgeInformation.matterbridgeDevVersion = packageJson.version;
|
|
1113
912
|
this.log.debug(`Matterbridge Version: ${this.matterbridgeVersion}`);
|
|
1114
|
-
// Matterbridge latest version (will be set in the checkUpdate function)
|
|
1115
913
|
if (this.nodeContext)
|
|
1116
914
|
this.matterbridgeLatestVersion = this.matterbridgeInformation.matterbridgeLatestVersion = await this.nodeContext.get('matterbridgeLatestVersion', this.matterbridgeVersion);
|
|
1117
915
|
this.log.debug(`Matterbridge Latest Version: ${this.matterbridgeLatestVersion}`);
|
|
1118
|
-
// Matterbridge dev version (will be set in the checkUpdate function)
|
|
1119
916
|
if (this.nodeContext)
|
|
1120
917
|
this.matterbridgeDevVersion = this.matterbridgeInformation.matterbridgeDevVersion = await this.nodeContext.get('matterbridgeDevVersion', this.matterbridgeVersion);
|
|
1121
918
|
this.log.debug(`Matterbridge Dev Version: ${this.matterbridgeDevVersion}`);
|
|
1122
|
-
// Current working directory
|
|
1123
919
|
const currentDir = process.cwd();
|
|
1124
920
|
this.log.debug(`Current Working Directory: ${currentDir}`);
|
|
1125
|
-
// Command line arguments (excluding 'node' and the script name)
|
|
1126
921
|
const cmdArgs = process.argv.slice(2).join(' ');
|
|
1127
922
|
this.log.debug(`Command Line Arguments: ${cmdArgs}`);
|
|
1128
923
|
}
|
|
1129
|
-
/**
|
|
1130
|
-
* Creates a MatterLogger function to show the matter.js log messages in AnsiLogger (for the frontend).
|
|
1131
|
-
*
|
|
1132
|
-
* @returns {Function} The MatterLogger function.
|
|
1133
|
-
*/
|
|
1134
924
|
createMatterLogger() {
|
|
1135
|
-
const matterLogger = new AnsiLogger({ logName: 'Matter', logTimestampFormat: 4
|
|
925
|
+
const matterLogger = new AnsiLogger({ logName: 'Matter', logTimestampFormat: 4, logLevel: "debug" });
|
|
1136
926
|
return (level, formattedLog) => {
|
|
1137
927
|
const logger = formattedLog.slice(44, 44 + 20).trim();
|
|
1138
928
|
const message = formattedLog.slice(65);
|
|
1139
929
|
matterLogger.logName = logger;
|
|
1140
930
|
switch (level) {
|
|
1141
931
|
case MatterLogLevel.DEBUG:
|
|
1142
|
-
matterLogger.log("debug"
|
|
932
|
+
matterLogger.log("debug", message);
|
|
1143
933
|
break;
|
|
1144
934
|
case MatterLogLevel.INFO:
|
|
1145
|
-
matterLogger.log("info"
|
|
935
|
+
matterLogger.log("info", message);
|
|
1146
936
|
break;
|
|
1147
937
|
case MatterLogLevel.NOTICE:
|
|
1148
|
-
matterLogger.log("notice"
|
|
938
|
+
matterLogger.log("notice", message);
|
|
1149
939
|
break;
|
|
1150
940
|
case MatterLogLevel.WARN:
|
|
1151
|
-
matterLogger.log("warn"
|
|
941
|
+
matterLogger.log("warn", message);
|
|
1152
942
|
break;
|
|
1153
943
|
case MatterLogLevel.ERROR:
|
|
1154
|
-
matterLogger.log("error"
|
|
944
|
+
matterLogger.log("error", message);
|
|
1155
945
|
break;
|
|
1156
946
|
case MatterLogLevel.FATAL:
|
|
1157
|
-
matterLogger.log("fatal"
|
|
947
|
+
matterLogger.log("fatal", message);
|
|
1158
948
|
break;
|
|
1159
949
|
}
|
|
1160
950
|
};
|
|
1161
951
|
}
|
|
1162
|
-
/**
|
|
1163
|
-
* Creates a Matter File Logger.
|
|
1164
|
-
*
|
|
1165
|
-
* @param {string} filePath - The path to the log file.
|
|
1166
|
-
* @param {boolean} [unlink] - Whether to unlink the log file before creating a new one.
|
|
1167
|
-
* @returns {Function} - A function that logs formatted messages to the log file.
|
|
1168
|
-
*/
|
|
1169
952
|
async createMatterFileLogger(filePath, unlink = false) {
|
|
1170
|
-
// 2024-08-21 08:55:19.488 DEBUG InteractionMessenger Sending DataReport chunk with 28 attributes and 0 events: 1004 bytes
|
|
1171
953
|
let fileSize = 0;
|
|
1172
954
|
if (unlink) {
|
|
1173
955
|
try {
|
|
@@ -1178,12 +960,10 @@ export class Matterbridge extends EventEmitter {
|
|
|
1178
960
|
}
|
|
1179
961
|
}
|
|
1180
962
|
return async (level, formattedLog) => {
|
|
1181
|
-
/* istanbul ignore if */
|
|
1182
963
|
if (fileSize > 100000000) {
|
|
1183
|
-
return;
|
|
964
|
+
return;
|
|
1184
965
|
}
|
|
1185
966
|
fileSize += formattedLog.length;
|
|
1186
|
-
/* istanbul ignore if */
|
|
1187
967
|
if (fileSize > 100000000) {
|
|
1188
968
|
await fs.appendFile(filePath, `Logging on file has been stopped because the file size is greater than 100MB.` + os.EOL);
|
|
1189
969
|
return;
|
|
@@ -1216,27 +996,12 @@ export class Matterbridge extends EventEmitter {
|
|
|
1216
996
|
}
|
|
1217
997
|
};
|
|
1218
998
|
}
|
|
1219
|
-
/**
|
|
1220
|
-
* Restarts the process by exiting the current instance and loading a new instance (/api/restart).
|
|
1221
|
-
*
|
|
1222
|
-
* @returns {Promise<void>} A promise that resolves when the restart is completed.
|
|
1223
|
-
*/
|
|
1224
999
|
async restartProcess() {
|
|
1225
1000
|
await this.cleanup('restarting...', true);
|
|
1226
1001
|
}
|
|
1227
|
-
/**
|
|
1228
|
-
* Shut down the process (/api/shutdown).
|
|
1229
|
-
*
|
|
1230
|
-
* @returns {Promise<void>} A promise that resolves when the shutdown is completed.
|
|
1231
|
-
*/
|
|
1232
1002
|
async shutdownProcess() {
|
|
1233
1003
|
await this.cleanup('shutting down...', false);
|
|
1234
1004
|
}
|
|
1235
|
-
/**
|
|
1236
|
-
* Update matterbridge and shut down the process (virtual device 'Update Matterbridge').
|
|
1237
|
-
*
|
|
1238
|
-
* @returns {Promise<void>} A promise that resolves when the update is completed.
|
|
1239
|
-
*/
|
|
1240
1005
|
async updateProcess() {
|
|
1241
1006
|
this.log.info('Updating matterbridge...');
|
|
1242
1007
|
try {
|
|
@@ -1250,13 +1015,6 @@ export class Matterbridge extends EventEmitter {
|
|
|
1250
1015
|
this.frontend.wssSendRestartRequired();
|
|
1251
1016
|
await this.cleanup('updating...', false);
|
|
1252
1017
|
}
|
|
1253
|
-
/**
|
|
1254
|
-
* Unregister all devices and shut down the process (/api/unregister).
|
|
1255
|
-
*
|
|
1256
|
-
* @param {number} [timeout] - The timeout duration to wait for the message exchange to complete in milliseconds. Default is 1000.
|
|
1257
|
-
*
|
|
1258
|
-
* @returns {Promise<void>} A promise that resolves when the cleanup is completed.
|
|
1259
|
-
*/
|
|
1260
1018
|
async unregisterAndShutdownProcess(timeout = 1000) {
|
|
1261
1019
|
this.log.info('Unregistering all devices and shutting down...');
|
|
1262
1020
|
for (const plugin of this.plugins.array()) {
|
|
@@ -1270,71 +1028,46 @@ export class Matterbridge extends EventEmitter {
|
|
|
1270
1028
|
await this.removeAllBridgedEndpoints(plugin.name, 100);
|
|
1271
1029
|
}
|
|
1272
1030
|
this.log.debug('Waiting for the MessageExchange to finish...');
|
|
1273
|
-
await wait(timeout);
|
|
1031
|
+
await wait(timeout);
|
|
1274
1032
|
this.log.debug('Cleaning up and shutting down...');
|
|
1275
1033
|
await this.cleanup('unregistered all devices and shutting down...', false, timeout);
|
|
1276
1034
|
}
|
|
1277
|
-
/**
|
|
1278
|
-
* Reset commissioning and shut down the process (/api/reset).
|
|
1279
|
-
*
|
|
1280
|
-
* @returns {Promise<void>} A promise that resolves when the cleanup is completed.
|
|
1281
|
-
*/
|
|
1282
1035
|
async shutdownProcessAndReset() {
|
|
1283
1036
|
await this.cleanup('shutting down with reset...', false);
|
|
1284
1037
|
}
|
|
1285
|
-
/**
|
|
1286
|
-
* Factory reset and shut down the process (/api/factory-reset).
|
|
1287
|
-
*
|
|
1288
|
-
* @returns {Promise<void>} A promise that resolves when the cleanup is completed.
|
|
1289
|
-
*/
|
|
1290
1038
|
async shutdownProcessAndFactoryReset() {
|
|
1291
1039
|
await this.cleanup('shutting down with factory reset...', false);
|
|
1292
1040
|
}
|
|
1293
|
-
/**
|
|
1294
|
-
* Cleans up the Matterbridge instance.
|
|
1295
|
-
*
|
|
1296
|
-
* @param {string} message - The cleanup message.
|
|
1297
|
-
* @param {boolean} [restart] - Indicates whether to restart the instance after cleanup. Default is `false`.
|
|
1298
|
-
* @param {number} [timeout] - The timeout duration to wait for the message exchange to complete in milliseconds. Default is 1000.
|
|
1299
|
-
*
|
|
1300
|
-
* @returns {Promise<void>} A promise that resolves when the cleanup is completed.
|
|
1301
|
-
*/
|
|
1302
1041
|
async cleanup(message, restart = false, timeout = 1000) {
|
|
1303
1042
|
if (this.initialized && !this.hasCleanupStarted) {
|
|
1304
1043
|
this.emit('cleanup_started');
|
|
1305
1044
|
this.hasCleanupStarted = true;
|
|
1306
1045
|
this.log.info(message);
|
|
1307
|
-
// Clear the start matter interval
|
|
1308
1046
|
if (this.startMatterInterval) {
|
|
1309
1047
|
clearInterval(this.startMatterInterval);
|
|
1310
1048
|
this.startMatterInterval = undefined;
|
|
1311
1049
|
this.log.debug('Start matter interval cleared');
|
|
1312
1050
|
}
|
|
1313
|
-
// Clear the check update timeout
|
|
1314
1051
|
if (this.checkUpdateTimeout) {
|
|
1315
1052
|
clearTimeout(this.checkUpdateTimeout);
|
|
1316
1053
|
this.checkUpdateTimeout = undefined;
|
|
1317
1054
|
this.log.debug('Check update timeout cleared');
|
|
1318
1055
|
}
|
|
1319
|
-
// Clear the check update interval
|
|
1320
1056
|
if (this.checkUpdateInterval) {
|
|
1321
1057
|
clearInterval(this.checkUpdateInterval);
|
|
1322
1058
|
this.checkUpdateInterval = undefined;
|
|
1323
1059
|
this.log.debug('Check update interval cleared');
|
|
1324
1060
|
}
|
|
1325
|
-
// Clear the configure timeout
|
|
1326
1061
|
if (this.configureTimeout) {
|
|
1327
1062
|
clearTimeout(this.configureTimeout);
|
|
1328
1063
|
this.configureTimeout = undefined;
|
|
1329
1064
|
this.log.debug('Matterbridge configure timeout cleared');
|
|
1330
1065
|
}
|
|
1331
|
-
// Clear the reachability timeout
|
|
1332
1066
|
if (this.reachabilityTimeout) {
|
|
1333
1067
|
clearTimeout(this.reachabilityTimeout);
|
|
1334
1068
|
this.reachabilityTimeout = undefined;
|
|
1335
1069
|
this.log.debug('Matterbridge reachability timeout cleared');
|
|
1336
1070
|
}
|
|
1337
|
-
// Call the shutdown method of each plugin and clear the plugins reachability timeout
|
|
1338
1071
|
for (const plugin of this.plugins) {
|
|
1339
1072
|
if (!plugin.enabled || plugin.error)
|
|
1340
1073
|
continue;
|
|
@@ -1345,7 +1078,6 @@ export class Matterbridge extends EventEmitter {
|
|
|
1345
1078
|
this.log.debug(`Plugin ${plg}${plugin.name}${db} reachability timeout cleared`);
|
|
1346
1079
|
}
|
|
1347
1080
|
}
|
|
1348
|
-
// Stop matter server nodes
|
|
1349
1081
|
this.log.notice(`Stopping matter server nodes in ${this.bridgeMode} mode...`);
|
|
1350
1082
|
this.log.debug('Waiting for the MessageExchange to finish...');
|
|
1351
1083
|
await wait(timeout, 'Waiting for the MessageExchange to finish...', true);
|
|
@@ -1370,7 +1102,6 @@ export class Matterbridge extends EventEmitter {
|
|
|
1370
1102
|
}
|
|
1371
1103
|
}
|
|
1372
1104
|
this.log.notice('Stopped matter server nodes');
|
|
1373
|
-
// Matter commisioning reset
|
|
1374
1105
|
if (message === 'shutting down with reset...') {
|
|
1375
1106
|
this.log.info('Resetting Matterbridge commissioning information...');
|
|
1376
1107
|
await this.matterStorageManager?.createContext('events')?.clearAll();
|
|
@@ -1380,7 +1111,6 @@ export class Matterbridge extends EventEmitter {
|
|
|
1380
1111
|
await this.matterbridgeContext?.clearAll();
|
|
1381
1112
|
this.log.info('Matter storage reset done! Remove the bridge from the controller.');
|
|
1382
1113
|
}
|
|
1383
|
-
// Unregister all devices
|
|
1384
1114
|
if (message === 'unregistered all devices and shutting down...') {
|
|
1385
1115
|
if (this.bridgeMode === 'bridge') {
|
|
1386
1116
|
await this.matterStorageManager?.createContext('root')?.createContext('parts')?.createContext('Matterbridge')?.createContext('parts')?.clearAll();
|
|
@@ -1398,36 +1128,18 @@ export class Matterbridge extends EventEmitter {
|
|
|
1398
1128
|
}
|
|
1399
1129
|
this.log.info('Matter storage reset done!');
|
|
1400
1130
|
}
|
|
1401
|
-
// Stop matter storage
|
|
1402
1131
|
await this.stopMatterStorage();
|
|
1403
|
-
// Stop the frontend
|
|
1404
1132
|
await this.frontend.stop();
|
|
1405
|
-
// Remove the matterfilelogger
|
|
1406
1133
|
try {
|
|
1407
1134
|
Logger.removeLogger('matterfilelogger');
|
|
1408
1135
|
}
|
|
1409
1136
|
catch (error) {
|
|
1410
1137
|
this.log.debug(`Error removing the matterfilelogger for file ${CYAN}${path.join(this.matterbridgeDirectory, this.matterLoggerFile)}${db}: ${error instanceof Error ? error.message : String(error)}`);
|
|
1411
1138
|
}
|
|
1412
|
-
// Close the matterbridge node storage and context
|
|
1413
1139
|
if (this.nodeStorage && this.nodeContext) {
|
|
1414
|
-
/*
|
|
1415
|
-
TODO: Implement serialization of registered devices in edge mode
|
|
1416
|
-
this.log.info('Saving registered devices...');
|
|
1417
|
-
const serializedRegisteredDevices: SerializedMatterbridgeEndpoint[] = [];
|
|
1418
|
-
this.devices.forEach(async (device) => {
|
|
1419
|
-
const serializedMatterbridgeDevice = MatterbridgeEndpoint.serialize(device);
|
|
1420
|
-
// this.log.info(`- ${serializedMatterbridgeDevice.deviceName}${rs}\n`, serializedMatterbridgeDevice);
|
|
1421
|
-
if (serializedMatterbridgeDevice) serializedRegisteredDevices.push(serializedMatterbridgeDevice);
|
|
1422
|
-
});
|
|
1423
|
-
await this.nodeContext.set<SerializedMatterbridgeEndpoint[]>('devices', serializedRegisteredDevices);
|
|
1424
|
-
this.log.info(`Saved registered devices (${serializedRegisteredDevices?.length})`);
|
|
1425
|
-
*/
|
|
1426
|
-
// Clear nodeContext and nodeStorage (they just need 1000ms to write the data to disk)
|
|
1427
1140
|
this.log.debug(`Closing node storage context for ${plg}Matterbridge${db}...`);
|
|
1428
1141
|
await this.nodeContext.close();
|
|
1429
1142
|
this.nodeContext = undefined;
|
|
1430
|
-
// Clear nodeContext for each plugin (they just need 1000ms to write the data to disk)
|
|
1431
1143
|
for (const plugin of this.plugins) {
|
|
1432
1144
|
if (plugin.nodeContext) {
|
|
1433
1145
|
this.log.debug(`Closing node storage context for plugin ${plg}${plugin.name}${db}...`);
|
|
@@ -1444,10 +1156,8 @@ export class Matterbridge extends EventEmitter {
|
|
|
1444
1156
|
}
|
|
1445
1157
|
this.plugins.clear();
|
|
1446
1158
|
this.devices.clear();
|
|
1447
|
-
// Factory reset
|
|
1448
1159
|
if (message === 'shutting down with factory reset...') {
|
|
1449
1160
|
try {
|
|
1450
|
-
// Delete matter storage directory with its subdirectories and backup
|
|
1451
1161
|
const dir = path.join(this.matterbridgeDirectory, this.matterStorageName);
|
|
1452
1162
|
this.log.info(`Removing matter storage directory: ${dir}`);
|
|
1453
1163
|
await fs.rm(dir, { recursive: true });
|
|
@@ -1456,13 +1166,11 @@ export class Matterbridge extends EventEmitter {
|
|
|
1456
1166
|
await fs.rm(backup, { recursive: true });
|
|
1457
1167
|
}
|
|
1458
1168
|
catch (error) {
|
|
1459
|
-
// istanbul ignore next if
|
|
1460
1169
|
if (error instanceof Error && error.code !== 'ENOENT') {
|
|
1461
1170
|
this.log.error(`Error removing matter storage directory: ${error}`);
|
|
1462
1171
|
}
|
|
1463
1172
|
}
|
|
1464
1173
|
try {
|
|
1465
|
-
// Delete matterbridge storage directory with its subdirectories and backup
|
|
1466
1174
|
const dir = path.join(this.matterbridgeDirectory, this.nodeStorageName);
|
|
1467
1175
|
this.log.info(`Removing matterbridge storage directory: ${dir}`);
|
|
1468
1176
|
await fs.rm(dir, { recursive: true });
|
|
@@ -1471,20 +1179,18 @@ export class Matterbridge extends EventEmitter {
|
|
|
1471
1179
|
await fs.rm(backup, { recursive: true });
|
|
1472
1180
|
}
|
|
1473
1181
|
catch (error) {
|
|
1474
|
-
// istanbul ignore next if
|
|
1475
1182
|
if (error instanceof Error && error.code !== 'ENOENT') {
|
|
1476
1183
|
this.log.error(`Error removing matterbridge storage directory: ${error}`);
|
|
1477
1184
|
}
|
|
1478
1185
|
}
|
|
1479
1186
|
this.log.info('Factory reset done! Remove all paired fabrics from the controllers.');
|
|
1480
1187
|
}
|
|
1481
|
-
// Deregisters the process handlers
|
|
1482
1188
|
this.deregisterProcessHandlers();
|
|
1483
1189
|
if (restart) {
|
|
1484
1190
|
if (message === 'updating...') {
|
|
1485
1191
|
this.log.info('Cleanup completed. Updating...');
|
|
1486
1192
|
Matterbridge.instance = undefined;
|
|
1487
|
-
this.emit('update');
|
|
1193
|
+
this.emit('update');
|
|
1488
1194
|
}
|
|
1489
1195
|
else if (message === 'restarting...') {
|
|
1490
1196
|
this.log.info('Cleanup completed. Restarting...');
|
|
@@ -1505,13 +1211,6 @@ export class Matterbridge extends EventEmitter {
|
|
|
1505
1211
|
this.log.debug('Cleanup already started...');
|
|
1506
1212
|
}
|
|
1507
1213
|
}
|
|
1508
|
-
/**
|
|
1509
|
-
* Creates and configures the server node for a single not bridged device.
|
|
1510
|
-
*
|
|
1511
|
-
* @param {RegisteredPlugin} plugin - The plugin to configure.
|
|
1512
|
-
* @param {MatterbridgeEndpoint} device - The device to associate with the plugin.
|
|
1513
|
-
* @returns {Promise<void>} A promise that resolves when the server node for the accessory plugin is created and configured.
|
|
1514
|
-
*/
|
|
1515
1214
|
async createDeviceServerNode(plugin, device) {
|
|
1516
1215
|
if (device.mode === 'server' && !device.serverNode && device.deviceType && device.deviceName && device.vendorId && device.vendorName && device.productId && device.productName) {
|
|
1517
1216
|
this.log.debug(`Creating device ${plg}${plugin.name}${db}:${dev}${device.deviceName}${db} server node...`);
|
|
@@ -1522,13 +1221,6 @@ export class Matterbridge extends EventEmitter {
|
|
|
1522
1221
|
this.log.debug(`Added ${plg}${plugin.name}${db}:${dev}${device.deviceName}${db} to server node`);
|
|
1523
1222
|
}
|
|
1524
1223
|
}
|
|
1525
|
-
/**
|
|
1526
|
-
* Creates and configures the server node for an accessory plugin for a given device.
|
|
1527
|
-
*
|
|
1528
|
-
* @param {RegisteredPlugin} plugin - The plugin to configure.
|
|
1529
|
-
* @param {MatterbridgeEndpoint} device - The device to associate with the plugin.
|
|
1530
|
-
* @returns {Promise<void>} A promise that resolves when the server node for the accessory plugin is created and configured.
|
|
1531
|
-
*/
|
|
1532
1224
|
async createAccessoryPlugin(plugin, device) {
|
|
1533
1225
|
if (!plugin.locked && device.deviceType && device.deviceName && device.vendorId && device.productId && device.vendorName && device.productName) {
|
|
1534
1226
|
plugin.locked = true;
|
|
@@ -1540,12 +1232,6 @@ export class Matterbridge extends EventEmitter {
|
|
|
1540
1232
|
await plugin.serverNode.add(device);
|
|
1541
1233
|
}
|
|
1542
1234
|
}
|
|
1543
|
-
/**
|
|
1544
|
-
* Creates and configures the server node and the aggregator node for a dynamic plugin.
|
|
1545
|
-
*
|
|
1546
|
-
* @param {RegisteredPlugin} plugin - The plugin to configure.
|
|
1547
|
-
* @returns {Promise<void>} A promise that resolves when the server node and the aggregator node for the dynamic plugin is created and configured.
|
|
1548
|
-
*/
|
|
1549
1235
|
async createDynamicPlugin(plugin) {
|
|
1550
1236
|
if (!plugin.locked) {
|
|
1551
1237
|
plugin.locked = true;
|
|
@@ -1556,14 +1242,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
1556
1242
|
await plugin.serverNode.add(plugin.aggregatorNode);
|
|
1557
1243
|
}
|
|
1558
1244
|
}
|
|
1559
|
-
/**
|
|
1560
|
-
* Starts the Matterbridge in bridge mode.
|
|
1561
|
-
*
|
|
1562
|
-
* @private
|
|
1563
|
-
* @returns {Promise<void>} A promise that resolves when the Matterbridge is started.
|
|
1564
|
-
*/
|
|
1565
1245
|
async startBridge() {
|
|
1566
|
-
// Plugins are configured by a timer when matter server is started and plugin.configured is set to true
|
|
1567
1246
|
if (!this.matterStorageManager)
|
|
1568
1247
|
throw new Error('No storage manager initialized');
|
|
1569
1248
|
if (!this.matterbridgeContext)
|
|
@@ -1602,16 +1281,13 @@ export class Matterbridge extends EventEmitter {
|
|
|
1602
1281
|
clearInterval(this.startMatterInterval);
|
|
1603
1282
|
this.startMatterInterval = undefined;
|
|
1604
1283
|
this.log.debug('Cleared startMatterInterval interval for Matterbridge');
|
|
1605
|
-
|
|
1606
|
-
this.startServerNode(this.serverNode); // We don't await this, because the server node is started in the background
|
|
1607
|
-
// Start the Matter server node of single devices in mode 'server'
|
|
1284
|
+
this.startServerNode(this.serverNode);
|
|
1608
1285
|
for (const device of this.devices.array()) {
|
|
1609
1286
|
if (device.mode === 'server' && device.serverNode) {
|
|
1610
1287
|
this.log.debug(`Starting server node for device ${dev}${device.deviceName}${db} in server mode...`);
|
|
1611
|
-
this.startServerNode(device.serverNode);
|
|
1288
|
+
this.startServerNode(device.serverNode);
|
|
1612
1289
|
}
|
|
1613
1290
|
}
|
|
1614
|
-
// Configure the plugins
|
|
1615
1291
|
this.configureTimeout = setTimeout(async () => {
|
|
1616
1292
|
for (const plugin of this.plugins.array()) {
|
|
1617
1293
|
if (!plugin.enabled || !plugin.loaded || !plugin.started || plugin.error)
|
|
@@ -1629,25 +1305,16 @@ export class Matterbridge extends EventEmitter {
|
|
|
1629
1305
|
}
|
|
1630
1306
|
this.frontend.wssSendRefreshRequired('plugins');
|
|
1631
1307
|
}, 30 * 1000).unref();
|
|
1632
|
-
// Setting reachability to true
|
|
1633
1308
|
this.reachabilityTimeout = setTimeout(() => {
|
|
1634
1309
|
this.log.info(`Setting reachability to true for ${plg}Matterbridge${db}`);
|
|
1635
1310
|
if (this.aggregatorNode)
|
|
1636
1311
|
this.setAggregatorReachability(this.aggregatorNode, true);
|
|
1637
1312
|
this.frontend.wssSendRefreshRequired('reachability');
|
|
1638
1313
|
}, 60 * 1000).unref();
|
|
1639
|
-
// Logger.get('LogServerNode').info(this.serverNode);
|
|
1640
1314
|
this.emit('bridge_started');
|
|
1641
1315
|
this.log.notice('Matterbridge bridge started successfully');
|
|
1642
1316
|
}, this.startMatterIntervalMs);
|
|
1643
1317
|
}
|
|
1644
|
-
/**
|
|
1645
|
-
* Starts the Matterbridge in childbridge mode.
|
|
1646
|
-
*
|
|
1647
|
-
* @param {number} [delay] - The delay before starting the childbridge. Default is 1000 milliseconds.
|
|
1648
|
-
*
|
|
1649
|
-
* @returns {Promise<void>} A promise that resolves when the Matterbridge is started.
|
|
1650
|
-
*/
|
|
1651
1318
|
async startChildbridge(delay = 1000) {
|
|
1652
1319
|
if (!this.matterStorageManager)
|
|
1653
1320
|
throw new Error('No storage manager initialized');
|
|
@@ -1685,9 +1352,8 @@ export class Matterbridge extends EventEmitter {
|
|
|
1685
1352
|
clearInterval(this.startMatterInterval);
|
|
1686
1353
|
this.startMatterInterval = undefined;
|
|
1687
1354
|
if (delay > 0)
|
|
1688
|
-
await wait(delay);
|
|
1355
|
+
await wait(delay);
|
|
1689
1356
|
this.log.debug('Cleared startMatterInterval interval in childbridge mode');
|
|
1690
|
-
// Configure the plugins
|
|
1691
1357
|
this.configureTimeout = setTimeout(async () => {
|
|
1692
1358
|
for (const plugin of this.plugins.array()) {
|
|
1693
1359
|
if (!plugin.enabled || !plugin.loaded || !plugin.started || plugin.error)
|
|
@@ -1724,9 +1390,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
1724
1390
|
this.log.error(`Node storage context not found for plugin ${plg}${plugin.name}${er}`);
|
|
1725
1391
|
continue;
|
|
1726
1392
|
}
|
|
1727
|
-
|
|
1728
|
-
this.startServerNode(plugin.serverNode); // We don't await this, because the server node is started in the background
|
|
1729
|
-
// Setting reachability to true
|
|
1393
|
+
this.startServerNode(plugin.serverNode);
|
|
1730
1394
|
plugin.reachabilityTimeout = setTimeout(() => {
|
|
1731
1395
|
this.log.info(`Setting reachability to true for ${plg}${plugin.name}${nf} type ${plugin.type} server node ${plugin.serverNode !== undefined} aggregator node ${plugin.aggregatorNode !== undefined} device ${plugin.device !== undefined}`);
|
|
1732
1396
|
if (plugin.type === 'DynamicPlatform' && plugin.aggregatorNode)
|
|
@@ -1734,241 +1398,19 @@ export class Matterbridge extends EventEmitter {
|
|
|
1734
1398
|
this.frontend.wssSendRefreshRequired('reachability');
|
|
1735
1399
|
}, 60 * 1000).unref();
|
|
1736
1400
|
}
|
|
1737
|
-
// Start the Matter server node of single devices in mode 'server'
|
|
1738
1401
|
for (const device of this.devices.array()) {
|
|
1739
1402
|
if (device.mode === 'server' && device.serverNode) {
|
|
1740
1403
|
this.log.debug(`Starting server node for device ${dev}${device.deviceName}${db} in server mode...`);
|
|
1741
|
-
this.startServerNode(device.serverNode);
|
|
1404
|
+
this.startServerNode(device.serverNode);
|
|
1742
1405
|
}
|
|
1743
1406
|
}
|
|
1744
|
-
// Logger.get('LogServerNode').info(this.serverNode);
|
|
1745
1407
|
this.emit('childbridge_started');
|
|
1746
1408
|
this.log.notice('Matterbridge childbridge started successfully');
|
|
1747
1409
|
}, this.startMatterIntervalMs);
|
|
1748
1410
|
}
|
|
1749
|
-
/**
|
|
1750
|
-
* Starts the Matterbridge controller.
|
|
1751
|
-
*
|
|
1752
|
-
* @private
|
|
1753
|
-
* @returns {Promise<void>} A promise that resolves when the Matterbridge is started.
|
|
1754
|
-
*/
|
|
1755
1411
|
async startController() {
|
|
1756
|
-
/*
|
|
1757
|
-
if (!this.matterStorageManager) {
|
|
1758
|
-
this.log.error('No storage manager initialized');
|
|
1759
|
-
await this.cleanup('No storage manager initialized');
|
|
1760
|
-
return;
|
|
1761
|
-
}
|
|
1762
|
-
this.log.info('Creating context: mattercontrollerContext');
|
|
1763
|
-
this.controllerContext = this.matterStorageManager.createContext('mattercontrollerContext');
|
|
1764
|
-
if (!this.controllerContext) {
|
|
1765
|
-
this.log.error('No storage context mattercontrollerContext initialized');
|
|
1766
|
-
await this.cleanup('No storage context mattercontrollerContext initialized');
|
|
1767
|
-
return;
|
|
1768
|
-
}
|
|
1769
|
-
|
|
1770
|
-
this.log.debug('Starting matterbridge in mode', this.bridgeMode);
|
|
1771
|
-
this.matterServer = await this.createMatterServer(this.storageManager);
|
|
1772
|
-
this.log.info('Creating matter commissioning controller');
|
|
1773
|
-
this.commissioningController = new CommissioningController({
|
|
1774
|
-
autoConnect: false,
|
|
1775
|
-
});
|
|
1776
|
-
this.log.info('Adding matter commissioning controller to matter server');
|
|
1777
|
-
await this.matterServer.addCommissioningController(this.commissioningController);
|
|
1778
|
-
|
|
1779
|
-
this.log.info('Starting matter server');
|
|
1780
|
-
await this.matterServer.start();
|
|
1781
|
-
this.log.info('Matter server started');
|
|
1782
|
-
const commissioningOptions: ControllerCommissioningFlowOptions = {
|
|
1783
|
-
regulatoryLocation: GeneralCommissioning.RegulatoryLocationType.IndoorOutdoor,
|
|
1784
|
-
regulatoryCountryCode: 'XX',
|
|
1785
|
-
};
|
|
1786
|
-
const commissioningController = new CommissioningController({
|
|
1787
|
-
environment: {
|
|
1788
|
-
environment,
|
|
1789
|
-
id: uniqueId,
|
|
1790
|
-
},
|
|
1791
|
-
autoConnect: false, // Do not auto connect to the commissioned nodes
|
|
1792
|
-
adminFabricLabel,
|
|
1793
|
-
});
|
|
1794
|
-
|
|
1795
|
-
if (hasParameter('pairingcode')) {
|
|
1796
|
-
this.log.info('Pairing device with pairingcode:', getParameter('pairingcode'));
|
|
1797
|
-
const pairingCode = getParameter('pairingcode');
|
|
1798
|
-
const ip = this.controllerContext.has('ip') ? this.controllerContext.get<string>('ip') : undefined;
|
|
1799
|
-
const port = this.controllerContext.has('port') ? this.controllerContext.get<number>('port') : undefined;
|
|
1800
|
-
|
|
1801
|
-
let longDiscriminator, setupPin, shortDiscriminator;
|
|
1802
|
-
if (pairingCode !== undefined) {
|
|
1803
|
-
const pairingCodeCodec = ManualPairingCodeCodec.decode(pairingCode);
|
|
1804
|
-
shortDiscriminator = pairingCodeCodec.shortDiscriminator;
|
|
1805
|
-
longDiscriminator = undefined;
|
|
1806
|
-
setupPin = pairingCodeCodec.passcode;
|
|
1807
|
-
this.log.info(`Data extracted from pairing code: ${Logger.toJSON(pairingCodeCodec)}`);
|
|
1808
|
-
} else {
|
|
1809
|
-
longDiscriminator = await this.controllerContext.get('longDiscriminator', 3840);
|
|
1810
|
-
if (longDiscriminator > 4095) throw new Error('Discriminator value must be less than 4096');
|
|
1811
|
-
setupPin = this.controllerContext.get('pin', 20202021);
|
|
1812
|
-
}
|
|
1813
|
-
if ((shortDiscriminator === undefined && longDiscriminator === undefined) || setupPin === undefined) {
|
|
1814
|
-
throw new Error('Please specify the longDiscriminator of the device to commission with -longDiscriminator or provide a valid passcode with -passcode');
|
|
1815
|
-
}
|
|
1816
|
-
|
|
1817
|
-
const options = {
|
|
1818
|
-
commissioning: commissioningOptions,
|
|
1819
|
-
discovery: {
|
|
1820
|
-
knownAddress: ip !== undefined && port !== undefined ? { ip, port, type: 'udp' } : undefined,
|
|
1821
|
-
identifierData: longDiscriminator !== undefined ? { longDiscriminator } : shortDiscriminator !== undefined ? { shortDiscriminator } : {},
|
|
1822
|
-
},
|
|
1823
|
-
passcode: setupPin,
|
|
1824
|
-
} as NodeCommissioningOptions;
|
|
1825
|
-
this.log.info('Commissioning with options:', options);
|
|
1826
|
-
const nodeId = await this.commissioningController.commissionNode(options);
|
|
1827
|
-
this.log.info(`Commissioning successfully done with nodeId: ${nodeId}`);
|
|
1828
|
-
this.log.info('ActiveSessionInformation:', this.commissioningController.getActiveSessionInformation());
|
|
1829
|
-
} // (hasParameter('pairingcode'))
|
|
1830
|
-
|
|
1831
|
-
if (hasParameter('unpairall')) {
|
|
1832
|
-
this.log.info('***Commissioning controller unpairing all nodes...');
|
|
1833
|
-
const nodeIds = this.commissioningController.getCommissionedNodes();
|
|
1834
|
-
for (const nodeId of nodeIds) {
|
|
1835
|
-
this.log.info('***Commissioning controller unpairing node:', nodeId);
|
|
1836
|
-
await this.commissioningController.removeNode(nodeId);
|
|
1837
|
-
}
|
|
1838
|
-
return;
|
|
1839
|
-
}
|
|
1840
|
-
|
|
1841
|
-
if (hasParameter('discover')) {
|
|
1842
|
-
// const discover = await this.commissioningController.discoverCommissionableDevices({ productId: 0x8000, deviceType: 0xfff1 });
|
|
1843
|
-
// console.log(discover);
|
|
1844
|
-
}
|
|
1845
|
-
|
|
1846
|
-
if (!this.commissioningController.isCommissioned()) {
|
|
1847
|
-
this.log.info('***Commissioning controller is not commissioned: use matterbridge -controller -pairingcode [pairingcode] to commission a device');
|
|
1848
|
-
return;
|
|
1849
|
-
}
|
|
1850
|
-
|
|
1851
|
-
const nodeIds = this.commissioningController.getCommissionedNodes();
|
|
1852
|
-
this.log.info(`***Commissioning controller is commissioned ${this.commissioningController.isCommissioned()} and has ${nodeIds.length} nodes commisioned: `);
|
|
1853
|
-
for (const nodeId of nodeIds) {
|
|
1854
|
-
this.log.info(`***Connecting to commissioned node: ${nodeId}`);
|
|
1855
|
-
|
|
1856
|
-
const node = await this.commissioningController.connectNode(nodeId, {
|
|
1857
|
-
autoSubscribe: false,
|
|
1858
|
-
attributeChangedCallback: (peerNodeId, { path: { nodeId, clusterId, endpointId, attributeName }, value }) =>
|
|
1859
|
-
this.log.info(`***Commissioning controller attributeChangedCallback ${peerNodeId}: attribute ${nodeId}/${endpointId}/${clusterId}/${attributeName} changed to ${Logger.toJSON(value)}`),
|
|
1860
|
-
eventTriggeredCallback: (peerNodeId, { path: { nodeId, clusterId, endpointId, eventName }, events }) =>
|
|
1861
|
-
this.log.info(`***Commissioning controller eventTriggeredCallback ${peerNodeId}: Event ${nodeId}/${endpointId}/${clusterId}/${eventName} triggered with ${Logger.toJSON(events)}`),
|
|
1862
|
-
stateInformationCallback: (peerNodeId, info) => {
|
|
1863
|
-
switch (info) {
|
|
1864
|
-
case NodeStateInformation.Connected:
|
|
1865
|
-
this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} connected`);
|
|
1866
|
-
break;
|
|
1867
|
-
case NodeStateInformation.Disconnected:
|
|
1868
|
-
this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} disconnected`);
|
|
1869
|
-
break;
|
|
1870
|
-
case NodeStateInformation.Reconnecting:
|
|
1871
|
-
this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} reconnecting`);
|
|
1872
|
-
break;
|
|
1873
|
-
case NodeStateInformation.WaitingForDeviceDiscovery:
|
|
1874
|
-
this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} waiting for device discovery`);
|
|
1875
|
-
break;
|
|
1876
|
-
case NodeStateInformation.StructureChanged:
|
|
1877
|
-
this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} structure changed`);
|
|
1878
|
-
break;
|
|
1879
|
-
case NodeStateInformation.Decommissioned:
|
|
1880
|
-
this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} decommissioned`);
|
|
1881
|
-
break;
|
|
1882
|
-
default:
|
|
1883
|
-
this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} NodeStateInformation.${info}`);
|
|
1884
|
-
break;
|
|
1885
|
-
}
|
|
1886
|
-
},
|
|
1887
|
-
});
|
|
1888
|
-
|
|
1889
|
-
node.logStructure();
|
|
1890
|
-
|
|
1891
|
-
// Get the interaction client
|
|
1892
|
-
this.log.info('Getting the interaction client');
|
|
1893
|
-
const interactionClient = await node.getInteractionClient();
|
|
1894
|
-
let cluster;
|
|
1895
|
-
let attributes;
|
|
1896
|
-
|
|
1897
|
-
// Log BasicInformationCluster
|
|
1898
|
-
cluster = BasicInformationCluster;
|
|
1899
|
-
attributes = await interactionClient.getMultipleAttributes({
|
|
1900
|
-
attributes: [{ clusterId: cluster.id }],
|
|
1901
|
-
});
|
|
1902
|
-
if (attributes.length > 0) this.log.info(`Cluster: ${idn}${cluster.name}${rs}${nf} attributes:`);
|
|
1903
|
-
attributes.forEach((attribute) => {
|
|
1904
|
-
this.log.info(
|
|
1905
|
-
`- endpoint ${or}${attribute.path.endpointId}${nf} cluster ${hk}${getClusterNameById(attribute.path.clusterId)}${nf} (${hk}0x${attribute.path.clusterId.toString(16)}${nf}) attribute ${zb}${attribute.path.attributeName}${nf} (${zb}0x${attribute.path.attributeId.toString(16)}${nf}): ${typeof attribute.value === 'object' ? stringify(attribute.value) : attribute.value}`,
|
|
1906
|
-
);
|
|
1907
|
-
});
|
|
1908
|
-
|
|
1909
|
-
// Log PowerSourceCluster
|
|
1910
|
-
cluster = PowerSourceCluster;
|
|
1911
|
-
attributes = await interactionClient.getMultipleAttributes({
|
|
1912
|
-
attributes: [{ clusterId: cluster.id }],
|
|
1913
|
-
});
|
|
1914
|
-
if (attributes.length > 0) this.log.info(`Cluster: ${idn}${cluster.name}${rs}${nf} attributes:`);
|
|
1915
|
-
attributes.forEach((attribute) => {
|
|
1916
|
-
this.log.info(
|
|
1917
|
-
`- endpoint ${or}${attribute.path.endpointId}${nf} cluster ${hk}${getClusterNameById(attribute.path.clusterId)}${nf} (${hk}0x${attribute.path.clusterId.toString(16)}${nf}) attribute ${zb}${attribute.path.attributeName}${nf} (${zb}0x${attribute.path.attributeId.toString(16)}${nf}): ${typeof attribute.value === 'object' ? stringify(attribute.value) : attribute.value}`,
|
|
1918
|
-
);
|
|
1919
|
-
});
|
|
1920
|
-
|
|
1921
|
-
// Log ThreadNetworkDiagnostics
|
|
1922
|
-
cluster = ThreadNetworkDiagnosticsCluster;
|
|
1923
|
-
attributes = await interactionClient.getMultipleAttributes({
|
|
1924
|
-
attributes: [{ clusterId: cluster.id }],
|
|
1925
|
-
});
|
|
1926
|
-
if (attributes.length > 0) this.log.info(`Cluster: ${idn}${cluster.name}${rs}${nf} attributes:`);
|
|
1927
|
-
attributes.forEach((attribute) => {
|
|
1928
|
-
this.log.info(
|
|
1929
|
-
`- endpoint ${or}${attribute.path.endpointId}${nf} cluster ${hk}${getClusterNameById(attribute.path.clusterId)}${nf} (${hk}0x${attribute.path.clusterId.toString(16)}${nf}) attribute ${zb}${attribute.path.attributeName}${nf} (${zb}0x${attribute.path.attributeId.toString(16)}${nf}): ${typeof attribute.value === 'object' ? stringify(attribute.value) : attribute.value}`,
|
|
1930
|
-
);
|
|
1931
|
-
});
|
|
1932
|
-
|
|
1933
|
-
// Log SwitchCluster
|
|
1934
|
-
cluster = SwitchCluster;
|
|
1935
|
-
attributes = await interactionClient.getMultipleAttributes({
|
|
1936
|
-
attributes: [{ clusterId: cluster.id }],
|
|
1937
|
-
});
|
|
1938
|
-
if (attributes.length > 0) this.log.info(`Cluster: ${idn}${cluster.name}${rs}${nf} attributes:`);
|
|
1939
|
-
attributes.forEach((attribute) => {
|
|
1940
|
-
this.log.info(
|
|
1941
|
-
`- endpoint ${or}${attribute.path.endpointId}${nf} cluster ${hk}${getClusterNameById(attribute.path.clusterId)}${nf} (${hk}0x${attribute.path.clusterId.toString(16)}${nf}) attribute ${zb}${attribute.path.attributeName}${nf} (${zb}0x${attribute.path.attributeId.toString(16)}${nf}): ${typeof attribute.value === 'object' ? stringify(attribute.value) : attribute.value}`,
|
|
1942
|
-
);
|
|
1943
|
-
});
|
|
1944
|
-
|
|
1945
|
-
this.log.info('Subscribing to all attributes and events');
|
|
1946
|
-
await node.subscribeAllAttributesAndEvents({
|
|
1947
|
-
ignoreInitialTriggers: false,
|
|
1948
|
-
attributeChangedCallback: ({ path: { nodeId, clusterId, endpointId, attributeName }, version, value }) =>
|
|
1949
|
-
this.log.info(
|
|
1950
|
-
`***${db}Commissioning controller attributeChangedCallback version ${version}: attribute ${BLUE}${nodeId}${db}/${or}${endpointId}${db}/${hk}${getClusterNameById(clusterId)}${db}/${zb}${attributeName}${db} changed to ${typeof value === 'object' ? debugStringify(value ?? { none: true }) : value}`,
|
|
1951
|
-
),
|
|
1952
|
-
eventTriggeredCallback: ({ path: { nodeId, clusterId, endpointId, eventName }, events }) => {
|
|
1953
|
-
this.log.info(
|
|
1954
|
-
`***${db}Commissioning controller eventTriggeredCallback: event ${BLUE}${nodeId}${db}/${or}${endpointId}${db}/${hk}${getClusterNameById(clusterId)}${db}/${zb}${eventName}${db} triggered with ${debugStringify(events ?? { none: true })}`,
|
|
1955
|
-
);
|
|
1956
|
-
},
|
|
1957
|
-
});
|
|
1958
|
-
this.log.info('Subscribed to all attributes and events');
|
|
1959
|
-
}
|
|
1960
|
-
*/
|
|
1961
1412
|
}
|
|
1962
|
-
/** */
|
|
1963
|
-
/** Matter.js methods */
|
|
1964
|
-
/** */
|
|
1965
|
-
/**
|
|
1966
|
-
* Starts the matter storage with name Matterbridge, create the matterbridge context and performs a backup.
|
|
1967
|
-
*
|
|
1968
|
-
* @returns {Promise<void>} - A promise that resolves when the storage is started.
|
|
1969
|
-
*/
|
|
1970
1413
|
async startMatterStorage() {
|
|
1971
|
-
// Setup Matter storage
|
|
1972
1414
|
this.log.info(`Starting matter node storage...`);
|
|
1973
1415
|
this.matterStorageService = this.environment.get(StorageService);
|
|
1974
1416
|
this.log.info(`Matter node storage service created: ${this.matterStorageService.location}`);
|
|
@@ -1977,17 +1419,8 @@ export class Matterbridge extends EventEmitter {
|
|
|
1977
1419
|
this.matterbridgeContext = await this.createServerNodeContext('Matterbridge', 'Matterbridge', this.aggregatorDeviceType, this.aggregatorVendorId, this.aggregatorVendorName, this.aggregatorProductId, this.aggregatorProductName, this.aggregatorSerialNumber, this.aggregatorUniqueId);
|
|
1978
1420
|
this.matterbridgeInformation.matterbridgeSerialNumber = await this.matterbridgeContext.get('serialNumber', '');
|
|
1979
1421
|
this.log.info('Matter node storage started');
|
|
1980
|
-
// Backup matter storage since it is created/opened correctly
|
|
1981
1422
|
await this.backupMatterStorage(path.join(this.matterbridgeDirectory, this.matterStorageName), path.join(this.matterbridgeDirectory, this.matterStorageName + '.backup'));
|
|
1982
1423
|
}
|
|
1983
|
-
/**
|
|
1984
|
-
* Makes a backup copy of the specified matter storage directory.
|
|
1985
|
-
*
|
|
1986
|
-
* @param {string} storageName - The name of the storage directory to be backed up.
|
|
1987
|
-
* @param {string} backupName - The name of the backup directory to be created.
|
|
1988
|
-
* @private
|
|
1989
|
-
* @returns {Promise<void>} A promise that resolves when the has been done.
|
|
1990
|
-
*/
|
|
1991
1424
|
async backupMatterStorage(storageName, backupName) {
|
|
1992
1425
|
this.log.info('Creating matter node storage backup...');
|
|
1993
1426
|
try {
|
|
@@ -1998,11 +1431,6 @@ export class Matterbridge extends EventEmitter {
|
|
|
1998
1431
|
this.log.error(`Error creating matter node storage backup from ${storageName} to ${backupName}:`, error);
|
|
1999
1432
|
}
|
|
2000
1433
|
}
|
|
2001
|
-
/**
|
|
2002
|
-
* Stops the matter storage.
|
|
2003
|
-
*
|
|
2004
|
-
* @returns {Promise<void>} A promise that resolves when the storage is stopped.
|
|
2005
|
-
*/
|
|
2006
1434
|
async stopMatterStorage() {
|
|
2007
1435
|
this.log.info('Closing matter node storage...');
|
|
2008
1436
|
await this.matterStorageManager?.close();
|
|
@@ -2011,20 +1439,6 @@ export class Matterbridge extends EventEmitter {
|
|
|
2011
1439
|
this.matterbridgeContext = undefined;
|
|
2012
1440
|
this.log.info('Matter node storage closed');
|
|
2013
1441
|
}
|
|
2014
|
-
/**
|
|
2015
|
-
* Creates a server node storage context.
|
|
2016
|
-
*
|
|
2017
|
-
* @param {string} pluginName - The name of the plugin.
|
|
2018
|
-
* @param {string} deviceName - The name of the device.
|
|
2019
|
-
* @param {DeviceTypeId} deviceType - The device type of the device.
|
|
2020
|
-
* @param {number} vendorId - The vendor ID.
|
|
2021
|
-
* @param {string} vendorName - The vendor name.
|
|
2022
|
-
* @param {number} productId - The product ID.
|
|
2023
|
-
* @param {string} productName - The product name.
|
|
2024
|
-
* @param {string} [serialNumber] - The serial number of the device (optional).
|
|
2025
|
-
* @param {string} [uniqueId] - The unique ID of the device (optional).
|
|
2026
|
-
* @returns {Promise<StorageContext>} The storage context for the commissioning server.
|
|
2027
|
-
*/
|
|
2028
1442
|
async createServerNodeContext(pluginName, deviceName, deviceType, vendorId, vendorName, productId, productName, serialNumber, uniqueId) {
|
|
2029
1443
|
const { randomBytes } = await import('node:crypto');
|
|
2030
1444
|
if (!this.matterStorageService)
|
|
@@ -2058,15 +1472,6 @@ export class Matterbridge extends EventEmitter {
|
|
|
2058
1472
|
this.log.debug(`- hardwareVersion: ${await storageContext.get('hardwareVersion')} hardwareVersionString: ${await storageContext.get('hardwareVersionString')}`);
|
|
2059
1473
|
return storageContext;
|
|
2060
1474
|
}
|
|
2061
|
-
/**
|
|
2062
|
-
* Creates a server node.
|
|
2063
|
-
*
|
|
2064
|
-
* @param {StorageContext} storageContext - The storage context for the server node.
|
|
2065
|
-
* @param {number} [port] - The port number for the server node. Defaults to 5540.
|
|
2066
|
-
* @param {number} [passcode] - The passcode for the server node. Defaults to 20242025.
|
|
2067
|
-
* @param {number} [discriminator] - The discriminator for the server node. Defaults to 3850.
|
|
2068
|
-
* @returns {Promise<ServerNode<ServerNode.RootEndpoint>>} A promise that resolves to the created server node.
|
|
2069
|
-
*/
|
|
2070
1475
|
async createServerNode(storageContext, port = 5540, passcode = 20242025, discriminator = 3850) {
|
|
2071
1476
|
const storeId = await storageContext.get('storeId');
|
|
2072
1477
|
this.log.notice(`Creating server node for ${storeId} on port ${port} with passcode ${passcode} and discriminator ${discriminator}...`);
|
|
@@ -2076,37 +1481,24 @@ export class Matterbridge extends EventEmitter {
|
|
|
2076
1481
|
this.log.debug(`- uniqueId: ${await storageContext.get('uniqueId')}`);
|
|
2077
1482
|
this.log.debug(`- softwareVersion: ${await storageContext.get('softwareVersion')} softwareVersionString: ${await storageContext.get('softwareVersionString')}`);
|
|
2078
1483
|
this.log.debug(`- hardwareVersion: ${await storageContext.get('hardwareVersion')} hardwareVersionString: ${await storageContext.get('hardwareVersionString')}`);
|
|
2079
|
-
/**
|
|
2080
|
-
* Create a Matter ServerNode, which contains the Root Endpoint and all relevant data and configuration
|
|
2081
|
-
*/
|
|
2082
1484
|
const serverNode = await ServerNode.create({
|
|
2083
|
-
// Required: Give the Node a unique ID which is used to store the state of this node
|
|
2084
1485
|
id: storeId,
|
|
2085
|
-
// Provide Network relevant configuration like the port
|
|
2086
|
-
// Optional when operating only one device on a host, Default port is 5540
|
|
2087
1486
|
network: {
|
|
2088
1487
|
listeningAddressIpv4: this.ipv4address,
|
|
2089
1488
|
listeningAddressIpv6: this.ipv6address,
|
|
2090
1489
|
port,
|
|
2091
1490
|
},
|
|
2092
|
-
// Provide the certificate for the device
|
|
2093
1491
|
operationalCredentials: {
|
|
2094
1492
|
certification: this.certification,
|
|
2095
1493
|
},
|
|
2096
|
-
// Provide Commissioning relevant settings
|
|
2097
|
-
// Optional for development/testing purposes
|
|
2098
1494
|
commissioning: {
|
|
2099
1495
|
passcode,
|
|
2100
1496
|
discriminator,
|
|
2101
1497
|
},
|
|
2102
|
-
// Provide Node announcement settings
|
|
2103
|
-
// Optional: If Ommitted some development defaults are used
|
|
2104
1498
|
productDescription: {
|
|
2105
1499
|
name: await storageContext.get('deviceName'),
|
|
2106
1500
|
deviceType: DeviceTypeId(await storageContext.get('deviceType')),
|
|
2107
1501
|
},
|
|
2108
|
-
// Provide defaults for the BasicInformation cluster on the Root endpoint
|
|
2109
|
-
// Optional: If Omitted some development defaults are used
|
|
2110
1502
|
basicInformation: {
|
|
2111
1503
|
vendorId: VendorId(await storageContext.get('vendorId')),
|
|
2112
1504
|
vendorName: await storageContext.get('vendorName'),
|
|
@@ -2123,20 +1515,14 @@ export class Matterbridge extends EventEmitter {
|
|
|
2123
1515
|
reachable: true,
|
|
2124
1516
|
},
|
|
2125
1517
|
});
|
|
2126
|
-
/**
|
|
2127
|
-
* This event is triggered when the device is initially commissioned successfully.
|
|
2128
|
-
* This means: It is added to the first fabric.
|
|
2129
|
-
*/
|
|
2130
1518
|
serverNode.lifecycle.commissioned.on(() => {
|
|
2131
1519
|
this.log.notice(`Server node for ${storeId} was initially commissioned successfully!`);
|
|
2132
1520
|
clearTimeout(this.endAdvertiseTimeout);
|
|
2133
1521
|
});
|
|
2134
|
-
/** This event is triggered when all fabrics are removed from the device, usually it also does a factory reset then. */
|
|
2135
1522
|
serverNode.lifecycle.decommissioned.on(() => {
|
|
2136
1523
|
this.log.notice(`Server node for ${storeId} was fully decommissioned successfully!`);
|
|
2137
1524
|
clearTimeout(this.endAdvertiseTimeout);
|
|
2138
1525
|
});
|
|
2139
|
-
/** This event is triggered when the device went online. This means that it is discoverable in the network. */
|
|
2140
1526
|
serverNode.lifecycle.online.on(async () => {
|
|
2141
1527
|
this.log.notice(`Server node for ${storeId} is online`);
|
|
2142
1528
|
if (!serverNode.lifecycle.isCommissioned) {
|
|
@@ -2144,11 +1530,9 @@ export class Matterbridge extends EventEmitter {
|
|
|
2144
1530
|
const { qrPairingCode, manualPairingCode } = serverNode.state.commissioning.pairingCodes;
|
|
2145
1531
|
this.log.notice(`QR Code URL: https://project-chip.github.io/connectedhomeip/qrcode.html?data=${qrPairingCode}`);
|
|
2146
1532
|
this.log.notice(`Manual pairing code: ${manualPairingCode}`);
|
|
2147
|
-
// Set a timeout to show that advertising stops after 15 minutes if not commissioned
|
|
2148
1533
|
this.startEndAdvertiseTimer(serverNode);
|
|
2149
1534
|
}
|
|
2150
1535
|
else {
|
|
2151
|
-
// istanbul ignore next
|
|
2152
1536
|
this.log.notice(`Server node for ${storeId} is already commissioned. Waiting for controllers to connect ...`);
|
|
2153
1537
|
}
|
|
2154
1538
|
this.frontend.wssSendRefreshRequired('plugins');
|
|
@@ -2156,19 +1540,14 @@ export class Matterbridge extends EventEmitter {
|
|
|
2156
1540
|
this.frontend.wssSendSnackbarMessage(`${storeId} is online`, 5, 'success');
|
|
2157
1541
|
this.emit('online', storeId);
|
|
2158
1542
|
});
|
|
2159
|
-
/** This event is triggered when the device went offline. it is not longer discoverable or connectable in the network. */
|
|
2160
1543
|
serverNode.lifecycle.offline.on(() => {
|
|
2161
1544
|
this.log.notice(`Server node for ${storeId} is offline`);
|
|
2162
|
-
this.matterbridgeInformation.matterbridgeEndAdvertise = true;
|
|
1545
|
+
this.matterbridgeInformation.matterbridgeEndAdvertise = true;
|
|
2163
1546
|
this.frontend.wssSendRefreshRequired('plugins');
|
|
2164
1547
|
this.frontend.wssSendRefreshRequired('settings');
|
|
2165
1548
|
this.frontend.wssSendSnackbarMessage(`${storeId} is offline`, 5, 'warning');
|
|
2166
1549
|
this.emit('offline', storeId);
|
|
2167
1550
|
});
|
|
2168
|
-
/**
|
|
2169
|
-
* This event is triggered when a fabric is added, removed or updated on the device. Use this if more granular
|
|
2170
|
-
* information is needed.
|
|
2171
|
-
*/
|
|
2172
1551
|
serverNode.events.commissioning.fabricsChanged.on((fabricIndex, fabricAction) => {
|
|
2173
1552
|
let action = '';
|
|
2174
1553
|
switch (fabricAction) {
|
|
@@ -2185,22 +1564,14 @@ export class Matterbridge extends EventEmitter {
|
|
|
2185
1564
|
this.log.notice(`Commissioned fabric index ${fabricIndex} ${action} on server node for ${storeId}: ${debugStringify(serverNode.state.commissioning.fabrics[fabricIndex])}`);
|
|
2186
1565
|
this.frontend.wssSendRefreshRequired('fabrics');
|
|
2187
1566
|
});
|
|
2188
|
-
/**
|
|
2189
|
-
* This event is triggered when an operative new session was opened by a Controller.
|
|
2190
|
-
* It is not triggered for the initial commissioning process, just afterwards for real connections.
|
|
2191
|
-
*/
|
|
2192
1567
|
serverNode.events.sessions.opened.on((session) => {
|
|
2193
1568
|
this.log.notice(`Session opened on server node for ${storeId}: ${debugStringify(session)}`);
|
|
2194
1569
|
this.frontend.wssSendRefreshRequired('sessions');
|
|
2195
1570
|
});
|
|
2196
|
-
/**
|
|
2197
|
-
* This event is triggered when an operative session is closed by a Controller or because the Device goes offline.
|
|
2198
|
-
*/
|
|
2199
1571
|
serverNode.events.sessions.closed.on((session) => {
|
|
2200
1572
|
this.log.notice(`Session closed on server node for ${storeId}: ${debugStringify(session)}`);
|
|
2201
1573
|
this.frontend.wssSendRefreshRequired('sessions');
|
|
2202
1574
|
});
|
|
2203
|
-
/** This event is triggered when a subscription gets added or removed on an operative session. */
|
|
2204
1575
|
serverNode.events.sessions.subscriptionsChanged.on((session) => {
|
|
2205
1576
|
this.log.notice(`Session subscriptions changed on server node for ${storeId}: ${debugStringify(session)}`);
|
|
2206
1577
|
this.frontend.wssSendRefreshRequired('sessions');
|
|
@@ -2208,11 +1579,6 @@ export class Matterbridge extends EventEmitter {
|
|
|
2208
1579
|
this.log.info(`Created server node for ${storeId}`);
|
|
2209
1580
|
return serverNode;
|
|
2210
1581
|
}
|
|
2211
|
-
/**
|
|
2212
|
-
* Starts the 15 minutes timer to advice that advertising for the specified server node is ended.
|
|
2213
|
-
*
|
|
2214
|
-
* @param {ServerNode} [matterServerNode] - The server node to start.
|
|
2215
|
-
*/
|
|
2216
1582
|
startEndAdvertiseTimer(matterServerNode) {
|
|
2217
1583
|
if (this.endAdvertiseTimeout) {
|
|
2218
1584
|
this.log.debug(`Clear ${matterServerNode.id} server node end advertise timer`);
|
|
@@ -2231,25 +1597,12 @@ export class Matterbridge extends EventEmitter {
|
|
|
2231
1597
|
this.log.notice(`Advertising stopped. Restart to commission again.`);
|
|
2232
1598
|
}, 15 * 60 * 1000).unref();
|
|
2233
1599
|
}
|
|
2234
|
-
/**
|
|
2235
|
-
* Starts the specified server node.
|
|
2236
|
-
*
|
|
2237
|
-
* @param {ServerNode} [matterServerNode] - The server node to start.
|
|
2238
|
-
* @returns {Promise<void>} A promise that resolves when the server node has started.
|
|
2239
|
-
*/
|
|
2240
1600
|
async startServerNode(matterServerNode) {
|
|
2241
1601
|
if (!matterServerNode)
|
|
2242
1602
|
return;
|
|
2243
1603
|
this.log.notice(`Starting ${matterServerNode.id} server node`);
|
|
2244
1604
|
await matterServerNode.start();
|
|
2245
1605
|
}
|
|
2246
|
-
/**
|
|
2247
|
-
* Stops the specified server node.
|
|
2248
|
-
*
|
|
2249
|
-
* @param {ServerNode} matterServerNode - The server node to stop.
|
|
2250
|
-
* @param {number} [timeout] - The timeout in milliseconds for stopping the server node. Defaults to 30 seconds.
|
|
2251
|
-
* @returns {Promise<void>} A promise that resolves when the server node has stopped.
|
|
2252
|
-
*/
|
|
2253
1606
|
async stopServerNode(matterServerNode, timeout = 30000) {
|
|
2254
1607
|
if (!matterServerNode)
|
|
2255
1608
|
return;
|
|
@@ -2262,12 +1615,6 @@ export class Matterbridge extends EventEmitter {
|
|
|
2262
1615
|
this.log.error(`Failed to close ${matterServerNode.id} server node: ${error instanceof Error ? error.message : error}`);
|
|
2263
1616
|
}
|
|
2264
1617
|
}
|
|
2265
|
-
/**
|
|
2266
|
-
* Advertises the specified server node.
|
|
2267
|
-
*
|
|
2268
|
-
* @param {ServerNode} [matterServerNode] - The server node to advertise.
|
|
2269
|
-
* @returns {Promise<{ qrPairingCode: string, manualPairingCode: string } | undefined>} A promise that resolves to the pairing codes if the server node is advertised, or undefined if not.
|
|
2270
|
-
*/
|
|
2271
1618
|
async advertiseServerNode(matterServerNode) {
|
|
2272
1619
|
if (matterServerNode) {
|
|
2273
1620
|
await matterServerNode.env.get(DeviceCommissioner)?.allowBasicCommissioning();
|
|
@@ -2276,39 +1623,19 @@ export class Matterbridge extends EventEmitter {
|
|
|
2276
1623
|
return { qrPairingCode, manualPairingCode };
|
|
2277
1624
|
}
|
|
2278
1625
|
}
|
|
2279
|
-
/**
|
|
2280
|
-
* Stop advertise the specified server node.
|
|
2281
|
-
*
|
|
2282
|
-
* @param {ServerNode} [matterServerNode] - The server node to advertise.
|
|
2283
|
-
* @returns {Promise<void>} A promise that resolves when the server node has stopped advertising.
|
|
2284
|
-
*/
|
|
2285
1626
|
async stopAdvertiseServerNode(matterServerNode) {
|
|
2286
1627
|
if (matterServerNode && matterServerNode.lifecycle.isOnline) {
|
|
2287
1628
|
await matterServerNode.env.get(DeviceCommissioner)?.endCommissioning();
|
|
2288
1629
|
this.log.notice(`Stopped advertising for ${matterServerNode.id}`);
|
|
2289
1630
|
}
|
|
2290
1631
|
}
|
|
2291
|
-
/**
|
|
2292
|
-
* Creates an aggregator node with the specified storage context.
|
|
2293
|
-
*
|
|
2294
|
-
* @param {StorageContext} storageContext - The storage context for the aggregator node.
|
|
2295
|
-
* @returns {Promise<Endpoint<AggregatorEndpoint>>} A promise that resolves to the created aggregator node.
|
|
2296
|
-
*/
|
|
2297
1632
|
async createAggregatorNode(storageContext) {
|
|
2298
1633
|
this.log.notice(`Creating ${await storageContext.get('storeId')} aggregator...`);
|
|
2299
1634
|
const aggregatorNode = new Endpoint(AggregatorEndpoint, { id: `${await storageContext.get('storeId')}` });
|
|
2300
1635
|
this.log.info(`Created ${await storageContext.get('storeId')} aggregator`);
|
|
2301
1636
|
return aggregatorNode;
|
|
2302
1637
|
}
|
|
2303
|
-
/**
|
|
2304
|
-
* Adds a MatterbridgeEndpoint to the specified plugin.
|
|
2305
|
-
*
|
|
2306
|
-
* @param {string} pluginName - The name of the plugin.
|
|
2307
|
-
* @param {MatterbridgeEndpoint} device - The device to add as a bridged endpoint.
|
|
2308
|
-
* @returns {Promise<void>} A promise that resolves when the bridged endpoint has been added.
|
|
2309
|
-
*/
|
|
2310
1638
|
async addBridgedEndpoint(pluginName, device) {
|
|
2311
|
-
// Check if the plugin is registered
|
|
2312
1639
|
const plugin = this.plugins.get(pluginName);
|
|
2313
1640
|
if (!plugin) {
|
|
2314
1641
|
this.log.error(`Error adding bridged endpoint ${dev}${device.deviceName}${er} (${zb}${device.id}${er}) plugin ${plg}${pluginName}${er} not found`);
|
|
@@ -2328,7 +1655,6 @@ export class Matterbridge extends EventEmitter {
|
|
|
2328
1655
|
}
|
|
2329
1656
|
else if (this.bridgeMode === 'bridge') {
|
|
2330
1657
|
if (device.mode === 'matter') {
|
|
2331
|
-
// Register and add the device to the matterbridge server node
|
|
2332
1658
|
this.log.debug(`Adding matter endpoint ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} to Matterbridge server node...`);
|
|
2333
1659
|
if (!this.serverNode) {
|
|
2334
1660
|
this.log.error('Server node not found for Matterbridge');
|
|
@@ -2345,7 +1671,6 @@ export class Matterbridge extends EventEmitter {
|
|
|
2345
1671
|
}
|
|
2346
1672
|
}
|
|
2347
1673
|
else {
|
|
2348
|
-
// Register and add the device to the matterbridge aggregator node
|
|
2349
1674
|
this.log.debug(`Adding bridged endpoint ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} to Matterbridge aggregator node`);
|
|
2350
1675
|
if (!this.aggregatorNode) {
|
|
2351
1676
|
this.log.error('Aggregator node not found for Matterbridge');
|
|
@@ -2363,7 +1688,6 @@ export class Matterbridge extends EventEmitter {
|
|
|
2363
1688
|
}
|
|
2364
1689
|
}
|
|
2365
1690
|
else if (this.bridgeMode === 'childbridge') {
|
|
2366
|
-
// Register and add the device to the plugin server node
|
|
2367
1691
|
if (plugin.type === 'AccessoryPlatform') {
|
|
2368
1692
|
try {
|
|
2369
1693
|
this.log.debug(`Creating endpoint ${dev}${device.deviceName}${db} for AccessoryPlatform plugin ${plg}${plugin.name}${db} server node`);
|
|
@@ -2387,12 +1711,10 @@ export class Matterbridge extends EventEmitter {
|
|
|
2387
1711
|
return;
|
|
2388
1712
|
}
|
|
2389
1713
|
}
|
|
2390
|
-
// Register and add the device to the plugin aggregator node
|
|
2391
1714
|
if (plugin.type === 'DynamicPlatform') {
|
|
2392
1715
|
try {
|
|
2393
1716
|
this.log.debug(`Adding bridged endpoint ${dev}${device.deviceName}${db} for DynamicPlatform plugin ${plg}${plugin.name}${db} aggregator node`);
|
|
2394
1717
|
await this.createDynamicPlugin(plugin);
|
|
2395
|
-
// Fast plugins can add another device before the server node is ready, so we wait for the server node to be ready
|
|
2396
1718
|
await waiter(`createDynamicPlugin(${plugin.name})`, () => plugin.serverNode?.hasParts === true);
|
|
2397
1719
|
if (!plugin.aggregatorNode) {
|
|
2398
1720
|
this.log.error(`Aggregator node not found for plugin ${plg}${plugin.name}${er}`);
|
|
@@ -2415,28 +1737,17 @@ export class Matterbridge extends EventEmitter {
|
|
|
2415
1737
|
plugin.registeredDevices++;
|
|
2416
1738
|
if (plugin.addedDevices !== undefined)
|
|
2417
1739
|
plugin.addedDevices++;
|
|
2418
|
-
// Add the device to the DeviceManager
|
|
2419
1740
|
this.devices.set(device);
|
|
2420
|
-
// Subscribe to the reachable$Changed event
|
|
2421
1741
|
await this.subscribeAttributeChanged(plugin, device);
|
|
2422
1742
|
this.log.info(`Added and registered bridged endpoint (${plugin.registeredDevices}/${plugin.addedDevices}) ${dev}${device.deviceName}${nf} (${dev}${device.id}${nf}) for plugin ${plg}${pluginName}${nf}`);
|
|
2423
1743
|
}
|
|
2424
|
-
/**
|
|
2425
|
-
* Removes a MatterbridgeEndpoint from the specified plugin.
|
|
2426
|
-
*
|
|
2427
|
-
* @param {string} pluginName - The name of the plugin.
|
|
2428
|
-
* @param {MatterbridgeEndpoint} device - The device to remove as a bridged endpoint.
|
|
2429
|
-
* @returns {Promise<void>} A promise that resolves when the bridged endpoint has been removed.
|
|
2430
|
-
*/
|
|
2431
1744
|
async removeBridgedEndpoint(pluginName, device) {
|
|
2432
1745
|
this.log.debug(`Removing bridged endpoint ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} (${zb}${device.name}${db}) for plugin ${plg}${pluginName}${db}`);
|
|
2433
|
-
// Check if the plugin is registered
|
|
2434
1746
|
const plugin = this.plugins.get(pluginName);
|
|
2435
1747
|
if (!plugin) {
|
|
2436
1748
|
this.log.error(`Error removing bridged endpoint ${dev}${device.deviceName}${er} (${zb}${device.name}${er}) for plugin ${plg}${pluginName}${er}: plugin not found`);
|
|
2437
1749
|
return;
|
|
2438
1750
|
}
|
|
2439
|
-
// Register and add the device to the matterbridge aggregator node
|
|
2440
1751
|
if (this.bridgeMode === 'bridge') {
|
|
2441
1752
|
if (!this.aggregatorNode) {
|
|
2442
1753
|
this.log.error(`Error removing bridged endpoint ${dev}${device.deviceName}${er} (${zb}${device.name}${er}) for plugin ${plg}${pluginName}${er}: aggregator node not found`);
|
|
@@ -2451,7 +1762,6 @@ export class Matterbridge extends EventEmitter {
|
|
|
2451
1762
|
}
|
|
2452
1763
|
else if (this.bridgeMode === 'childbridge') {
|
|
2453
1764
|
if (plugin.type === 'AccessoryPlatform') {
|
|
2454
|
-
// Nothing to do here since the server node has no aggregator node but only the device itself
|
|
2455
1765
|
}
|
|
2456
1766
|
else if (plugin.type === 'DynamicPlatform') {
|
|
2457
1767
|
if (!plugin.aggregatorNode) {
|
|
@@ -2466,21 +1776,8 @@ export class Matterbridge extends EventEmitter {
|
|
|
2466
1776
|
if (plugin.addedDevices !== undefined)
|
|
2467
1777
|
plugin.addedDevices--;
|
|
2468
1778
|
}
|
|
2469
|
-
// Remove the device from the DeviceManager
|
|
2470
1779
|
this.devices.remove(device);
|
|
2471
1780
|
}
|
|
2472
|
-
/**
|
|
2473
|
-
* Removes all bridged endpoints from the specified plugin.
|
|
2474
|
-
*
|
|
2475
|
-
* @param {string} pluginName - The name of the plugin.
|
|
2476
|
-
* @param {number} [delay] - The delay in milliseconds between removing each bridged endpoint (default: 0).
|
|
2477
|
-
* @returns {Promise<void>} A promise that resolves when all bridged endpoints have been removed.
|
|
2478
|
-
*
|
|
2479
|
-
* @remarks
|
|
2480
|
-
* This method iterates through all devices in the DeviceManager and removes each bridged endpoint associated with the specified plugin.
|
|
2481
|
-
* It also applies a delay between each removal if specified.
|
|
2482
|
-
* The delay is useful to allow the controllers to receive a single subscription for each device removed.
|
|
2483
|
-
*/
|
|
2484
1781
|
async removeAllBridgedEndpoints(pluginName, delay = 0) {
|
|
2485
1782
|
this.log.debug(`Removing all bridged endpoints for plugin ${plg}${pluginName}${db}${delay > 0 ? ` with delay ${delay} ms` : ''}`);
|
|
2486
1783
|
for (const device of this.devices.array().filter((device) => device.plugin === pluginName)) {
|
|
@@ -2491,15 +1788,6 @@ export class Matterbridge extends EventEmitter {
|
|
|
2491
1788
|
if (delay > 0)
|
|
2492
1789
|
await wait(2000);
|
|
2493
1790
|
}
|
|
2494
|
-
/**
|
|
2495
|
-
* Subscribes to the attribute change event for the given device and plugin.
|
|
2496
|
-
* Specifically, it listens for changes in the 'reachable' attribute of the
|
|
2497
|
-
* BridgedDeviceBasicInformationServer cluster server of the bridged device or BasicInformationServer cluster server of server node.
|
|
2498
|
-
*
|
|
2499
|
-
* @param {RegisteredPlugin} plugin - The plugin associated with the device.
|
|
2500
|
-
* @param {MatterbridgeEndpoint} device - The device to subscribe to attribute changes for.
|
|
2501
|
-
* @returns {Promise<void>} A promise that resolves when the subscription is set up.
|
|
2502
|
-
*/
|
|
2503
1791
|
async subscribeAttributeChanged(plugin, device) {
|
|
2504
1792
|
this.log.info(`Subscribing attributes for endpoint ${dev}${device.deviceName}${nf} (${dev}${device.id}${nf}) plugin ${plg}${plugin.name}${nf}`);
|
|
2505
1793
|
if (this.bridgeMode === 'childbridge' && plugin.type === 'AccessoryPlatform' && plugin.serverNode) {
|
|
@@ -2515,12 +1803,6 @@ export class Matterbridge extends EventEmitter {
|
|
|
2515
1803
|
});
|
|
2516
1804
|
}
|
|
2517
1805
|
}
|
|
2518
|
-
/**
|
|
2519
|
-
* Sanitizes the fabric information by converting bigint properties to strings because `res.json` doesn't support bigint.
|
|
2520
|
-
*
|
|
2521
|
-
* @param {ExposedFabricInformation[]} fabricInfo - The array of exposed fabric information objects.
|
|
2522
|
-
* @returns {SanitizedExposedFabricInformation[]} An array of sanitized exposed fabric information objects.
|
|
2523
|
-
*/
|
|
2524
1806
|
sanitizeFabricInformations(fabricInfo) {
|
|
2525
1807
|
return fabricInfo.map((info) => {
|
|
2526
1808
|
return {
|
|
@@ -2534,12 +1816,6 @@ export class Matterbridge extends EventEmitter {
|
|
|
2534
1816
|
};
|
|
2535
1817
|
});
|
|
2536
1818
|
}
|
|
2537
|
-
/**
|
|
2538
|
-
* Sanitizes the session information by converting bigint properties to strings because `res.json` doesn't support bigint.
|
|
2539
|
-
*
|
|
2540
|
-
* @param {SessionsBehavior.Session[]} sessions - The array of session information objects.
|
|
2541
|
-
* @returns {SanitizedSession[]} An array of sanitized session information objects.
|
|
2542
|
-
*/
|
|
2543
1819
|
sanitizeSessionInformation(sessions) {
|
|
2544
1820
|
return sessions
|
|
2545
1821
|
.filter((session) => session.isPeerActive)
|
|
@@ -2566,21 +1842,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
2566
1842
|
};
|
|
2567
1843
|
});
|
|
2568
1844
|
}
|
|
2569
|
-
/**
|
|
2570
|
-
* Sets the reachability of the specified aggregator node bridged devices and trigger.
|
|
2571
|
-
*
|
|
2572
|
-
* @param {Endpoint<AggregatorEndpoint>} aggregatorNode - The aggregator node to set the reachability for.
|
|
2573
|
-
* @param {boolean} reachable - A boolean indicating the reachability status to set.
|
|
2574
|
-
*/
|
|
2575
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
2576
1845
|
async setAggregatorReachability(aggregatorNode, reachable) {
|
|
2577
|
-
/*
|
|
2578
|
-
for (const child of aggregatorNode.parts) {
|
|
2579
|
-
this.log.debug(`Setting reachability of ${(child as unknown as MatterbridgeEndpoint)?.deviceName} to ${reachable}`);
|
|
2580
|
-
await child.setStateOf(BridgedDeviceBasicInformationServer, { reachable });
|
|
2581
|
-
child.act((agent) => child.eventsOf(BridgedDeviceBasicInformationServer).reachableChanged.emit({ reachableNewValue: true }, agent.context));
|
|
2582
|
-
}
|
|
2583
|
-
*/
|
|
2584
1846
|
}
|
|
2585
1847
|
getVendorIdName = (vendorId) => {
|
|
2586
1848
|
if (!vendorId)
|
|
@@ -2620,11 +1882,10 @@ export class Matterbridge extends EventEmitter {
|
|
|
2620
1882
|
case 0x1488:
|
|
2621
1883
|
vendorName = '(ShortcutLabsFlic)';
|
|
2622
1884
|
break;
|
|
2623
|
-
case 65521:
|
|
1885
|
+
case 65521:
|
|
2624
1886
|
vendorName = '(MatterTest)';
|
|
2625
1887
|
break;
|
|
2626
1888
|
}
|
|
2627
1889
|
return vendorName;
|
|
2628
1890
|
};
|
|
2629
1891
|
}
|
|
2630
|
-
//# sourceMappingURL=matterbridge.js.map
|