@matterbridge/core 3.5.3 → 3.5.4-edge-20260211-1ea4e31
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/README.md +1 -1
- package/dist/cli.d.ts +0 -24
- package/dist/cli.js +1 -97
- package/dist/cliEmitter.d.ts +0 -36
- package/dist/cliEmitter.js +0 -37
- package/dist/cliHistory.d.ts +0 -42
- package/dist/cliHistory.js +0 -38
- package/dist/clusters/export.d.ts +0 -1
- package/dist/clusters/export.js +0 -2
- package/dist/deviceManager.d.ts +0 -108
- package/dist/deviceManager.js +1 -114
- package/dist/devices/airConditioner.d.ts +0 -75
- package/dist/devices/airConditioner.js +0 -57
- package/dist/devices/basicVideoPlayer.d.ts +0 -58
- package/dist/devices/basicVideoPlayer.js +1 -56
- package/dist/devices/batteryStorage.d.ts +0 -43
- package/dist/devices/batteryStorage.js +1 -48
- package/dist/devices/castingVideoPlayer.d.ts +0 -63
- package/dist/devices/castingVideoPlayer.js +2 -65
- package/dist/devices/cooktop.d.ts +0 -55
- package/dist/devices/cooktop.js +0 -56
- package/dist/devices/dishwasher.d.ts +0 -55
- package/dist/devices/dishwasher.js +0 -57
- package/dist/devices/evse.d.ts +0 -57
- package/dist/devices/evse.js +10 -74
- package/dist/devices/export.d.ts +0 -1
- package/dist/devices/export.js +0 -5
- package/dist/devices/extractorHood.d.ts +0 -41
- package/dist/devices/extractorHood.js +0 -43
- package/dist/devices/heatPump.d.ts +0 -43
- package/dist/devices/heatPump.js +2 -50
- package/dist/devices/laundryDryer.d.ts +0 -58
- package/dist/devices/laundryDryer.js +3 -62
- package/dist/devices/laundryWasher.d.ts +0 -64
- package/dist/devices/laundryWasher.js +4 -70
- package/dist/devices/microwaveOven.d.ts +1 -77
- package/dist/devices/microwaveOven.js +5 -88
- package/dist/devices/oven.d.ts +0 -82
- package/dist/devices/oven.js +0 -85
- package/dist/devices/refrigerator.d.ts +0 -100
- package/dist/devices/refrigerator.js +0 -102
- package/dist/devices/roboticVacuumCleaner.d.ts +0 -83
- package/dist/devices/roboticVacuumCleaner.js +9 -100
- package/dist/devices/solarPower.d.ts +0 -36
- package/dist/devices/solarPower.js +0 -38
- package/dist/devices/speaker.d.ts +0 -79
- package/dist/devices/speaker.js +0 -84
- package/dist/devices/temperatureControl.d.ts +0 -21
- package/dist/devices/temperatureControl.js +3 -24
- package/dist/devices/waterHeater.d.ts +0 -74
- package/dist/devices/waterHeater.js +2 -82
- package/dist/dgram/export.d.ts +0 -1
- package/dist/dgram/export.js +0 -1
- package/dist/export.d.ts +0 -23
- package/dist/export.js +0 -28
- package/dist/frontend.d.ts +0 -187
- package/dist/frontend.js +38 -539
- package/dist/helpers.d.ts +0 -43
- package/dist/helpers.js +0 -86
- package/dist/jestutils/export.d.ts +0 -1
- package/dist/jestutils/export.js +0 -1
- package/dist/jestutils/jestHelpers.d.ts +0 -259
- package/dist/jestutils/jestHelpers.js +14 -395
- package/dist/matter/behaviors.d.ts +0 -1
- package/dist/matter/behaviors.js +0 -2
- package/dist/matter/clusters.d.ts +0 -1
- package/dist/matter/clusters.js +0 -2
- package/dist/matter/devices.d.ts +0 -1
- package/dist/matter/devices.js +0 -2
- package/dist/matter/endpoints.d.ts +0 -1
- package/dist/matter/endpoints.js +0 -2
- package/dist/matter/export.d.ts +0 -1
- package/dist/matter/export.js +0 -2
- package/dist/matter/types.d.ts +0 -1
- package/dist/matter/types.js +0 -2
- package/dist/matterNode.d.ts +0 -258
- package/dist/matterNode.js +8 -356
- package/dist/matterbridge.d.ts +0 -389
- package/dist/matterbridge.js +48 -878
- package/dist/matterbridgeAccessoryPlatform.d.ts +0 -42
- package/dist/matterbridgeAccessoryPlatform.js +0 -50
- package/dist/matterbridgeBehaviors.d.ts +0 -24
- package/dist/matterbridgeBehaviors.js +5 -65
- package/dist/matterbridgeDeviceTypes.d.ts +0 -649
- package/dist/matterbridgeDeviceTypes.js +6 -673
- package/dist/matterbridgeDynamicPlatform.d.ts +0 -42
- package/dist/matterbridgeDynamicPlatform.js +0 -50
- package/dist/matterbridgeEndpoint.d.ts +0 -1369
- package/dist/matterbridgeEndpoint.js +56 -1514
- package/dist/matterbridgeEndpointHelpers.d.ts +0 -425
- package/dist/matterbridgeEndpointHelpers.js +20 -483
- package/dist/matterbridgeEndpointTypes.d.ts +0 -70
- package/dist/matterbridgeEndpointTypes.js +0 -25
- package/dist/matterbridgePlatform.d.ts +0 -434
- package/dist/matterbridgePlatform.js +1 -473
- package/dist/mb_coap.d.ts +0 -23
- package/dist/mb_coap.js +3 -41
- package/dist/mb_health.d.ts +0 -67
- package/dist/mb_health.js +0 -70
- package/dist/mb_mdns.d.ts +0 -23
- package/dist/mb_mdns.js +36 -94
- package/dist/pluginManager.d.ts +0 -307
- package/dist/pluginManager.js +6 -346
- package/dist/spawn.d.ts +0 -32
- package/dist/spawn.js +1 -71
- package/dist/utils/export.d.ts +0 -1
- package/dist/utils/export.js +0 -1
- package/package.json +27 -6
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/cliEmitter.d.ts.map +0 -1
- package/dist/cliEmitter.js.map +0 -1
- package/dist/cliHistory.d.ts.map +0 -1
- package/dist/cliHistory.js.map +0 -1
- package/dist/clusters/export.d.ts.map +0 -1
- package/dist/clusters/export.js.map +0 -1
- package/dist/crypto/attestationDecoder.d.ts +0 -180
- package/dist/crypto/attestationDecoder.d.ts.map +0 -1
- package/dist/crypto/attestationDecoder.js +0 -176
- package/dist/crypto/attestationDecoder.js.map +0 -1
- package/dist/crypto/declarationDecoder.d.ts +0 -72
- package/dist/crypto/declarationDecoder.d.ts.map +0 -1
- package/dist/crypto/declarationDecoder.js +0 -241
- package/dist/crypto/declarationDecoder.js.map +0 -1
- package/dist/crypto/extract/342/200/220cert/342/200/220extensions.d.ts +0 -9
- package/dist/crypto/extract/342/200/220cert/342/200/220extensions.d.ts.map +0 -1
- package/dist/crypto/extract/342/200/220cert/342/200/220extensions.js +0 -120
- package/dist/crypto/extract/342/200/220cert/342/200/220extensions.js.map +0 -1
- package/dist/crypto/read-extensions.d.ts +0 -2
- package/dist/crypto/read-extensions.d.ts.map +0 -1
- package/dist/crypto/read-extensions.js +0 -81
- package/dist/crypto/read-extensions.js.map +0 -1
- package/dist/crypto/testData.d.ts +0 -31
- package/dist/crypto/testData.d.ts.map +0 -1
- package/dist/crypto/testData.js +0 -131
- package/dist/crypto/testData.js.map +0 -1
- package/dist/crypto/walk-der.d.ts +0 -2
- package/dist/crypto/walk-der.d.ts.map +0 -1
- package/dist/crypto/walk-der.js +0 -165
- package/dist/crypto/walk-der.js.map +0 -1
- package/dist/deviceManager.d.ts.map +0 -1
- package/dist/deviceManager.js.map +0 -1
- package/dist/devices/airConditioner.d.ts.map +0 -1
- package/dist/devices/airConditioner.js.map +0 -1
- package/dist/devices/basicVideoPlayer.d.ts.map +0 -1
- package/dist/devices/basicVideoPlayer.js.map +0 -1
- package/dist/devices/batteryStorage.d.ts.map +0 -1
- package/dist/devices/batteryStorage.js.map +0 -1
- package/dist/devices/castingVideoPlayer.d.ts.map +0 -1
- package/dist/devices/castingVideoPlayer.js.map +0 -1
- package/dist/devices/cooktop.d.ts.map +0 -1
- package/dist/devices/cooktop.js.map +0 -1
- package/dist/devices/dishwasher.d.ts.map +0 -1
- package/dist/devices/dishwasher.js.map +0 -1
- package/dist/devices/evse.d.ts.map +0 -1
- package/dist/devices/evse.js.map +0 -1
- package/dist/devices/export.d.ts.map +0 -1
- package/dist/devices/export.js.map +0 -1
- package/dist/devices/extractorHood.d.ts.map +0 -1
- package/dist/devices/extractorHood.js.map +0 -1
- package/dist/devices/heatPump.d.ts.map +0 -1
- package/dist/devices/heatPump.js.map +0 -1
- package/dist/devices/laundryDryer.d.ts.map +0 -1
- package/dist/devices/laundryDryer.js.map +0 -1
- package/dist/devices/laundryWasher.d.ts.map +0 -1
- package/dist/devices/laundryWasher.js.map +0 -1
- package/dist/devices/microwaveOven.d.ts.map +0 -1
- package/dist/devices/microwaveOven.js.map +0 -1
- package/dist/devices/oven.d.ts.map +0 -1
- package/dist/devices/oven.js.map +0 -1
- package/dist/devices/refrigerator.d.ts.map +0 -1
- package/dist/devices/refrigerator.js.map +0 -1
- package/dist/devices/roboticVacuumCleaner.d.ts.map +0 -1
- package/dist/devices/roboticVacuumCleaner.js.map +0 -1
- package/dist/devices/solarPower.d.ts.map +0 -1
- package/dist/devices/solarPower.js.map +0 -1
- package/dist/devices/speaker.d.ts.map +0 -1
- package/dist/devices/speaker.js.map +0 -1
- package/dist/devices/temperatureControl.d.ts.map +0 -1
- package/dist/devices/temperatureControl.js.map +0 -1
- package/dist/devices/waterHeater.d.ts.map +0 -1
- package/dist/devices/waterHeater.js.map +0 -1
- package/dist/dgram/export.d.ts.map +0 -1
- package/dist/dgram/export.js.map +0 -1
- package/dist/export.d.ts.map +0 -1
- package/dist/export.js.map +0 -1
- package/dist/frontend.d.ts.map +0 -1
- package/dist/frontend.js.map +0 -1
- package/dist/helpers.d.ts.map +0 -1
- package/dist/helpers.js.map +0 -1
- package/dist/jestutils/export.d.ts.map +0 -1
- package/dist/jestutils/export.js.map +0 -1
- package/dist/jestutils/jestHelpers.d.ts.map +0 -1
- package/dist/jestutils/jestHelpers.js.map +0 -1
- package/dist/matter/behaviors.d.ts.map +0 -1
- package/dist/matter/behaviors.js.map +0 -1
- package/dist/matter/clusters.d.ts.map +0 -1
- package/dist/matter/clusters.js.map +0 -1
- package/dist/matter/devices.d.ts.map +0 -1
- package/dist/matter/devices.js.map +0 -1
- package/dist/matter/endpoints.d.ts.map +0 -1
- package/dist/matter/endpoints.js.map +0 -1
- package/dist/matter/export.d.ts.map +0 -1
- package/dist/matter/export.js.map +0 -1
- package/dist/matter/types.d.ts.map +0 -1
- package/dist/matter/types.js.map +0 -1
- package/dist/matterNode.d.ts.map +0 -1
- package/dist/matterNode.js.map +0 -1
- package/dist/matterbridge.d.ts.map +0 -1
- package/dist/matterbridge.js.map +0 -1
- package/dist/matterbridgeAccessoryPlatform.d.ts.map +0 -1
- package/dist/matterbridgeAccessoryPlatform.js.map +0 -1
- package/dist/matterbridgeBehaviors.d.ts.map +0 -1
- package/dist/matterbridgeBehaviors.js.map +0 -1
- package/dist/matterbridgeDeviceTypes.d.ts.map +0 -1
- package/dist/matterbridgeDeviceTypes.js.map +0 -1
- package/dist/matterbridgeDynamicPlatform.d.ts.map +0 -1
- package/dist/matterbridgeDynamicPlatform.js.map +0 -1
- package/dist/matterbridgeEndpoint.d.ts.map +0 -1
- package/dist/matterbridgeEndpoint.js.map +0 -1
- package/dist/matterbridgeEndpointHelpers.d.ts.map +0 -1
- package/dist/matterbridgeEndpointHelpers.js.map +0 -1
- package/dist/matterbridgeEndpointTypes.d.ts.map +0 -1
- package/dist/matterbridgeEndpointTypes.js.map +0 -1
- package/dist/matterbridgePlatform.d.ts.map +0 -1
- package/dist/matterbridgePlatform.js.map +0 -1
- package/dist/mb_coap.d.ts.map +0 -1
- package/dist/mb_coap.js.map +0 -1
- package/dist/mb_health.d.ts.map +0 -1
- package/dist/mb_health.js.map +0 -1
- package/dist/mb_mdns.d.ts.map +0 -1
- package/dist/mb_mdns.js.map +0 -1
- package/dist/pluginManager.d.ts.map +0 -1
- package/dist/pluginManager.js.map +0 -1
- package/dist/spawn.d.ts.map +0 -1
- package/dist/spawn.js.map +0 -1
- package/dist/utils/export.d.ts.map +0 -1
- package/dist/utils/export.js.map +0 -1
- package/dist/workers/brand.d.ts +0 -25
- package/dist/workers/brand.d.ts.map +0 -1
- package/dist/workers/brand.extend.d.ts +0 -10
- package/dist/workers/brand.extend.d.ts.map +0 -1
- package/dist/workers/brand.extend.js +0 -15
- package/dist/workers/brand.extend.js.map +0 -1
- package/dist/workers/brand.invalid.d.ts +0 -9
- package/dist/workers/brand.invalid.d.ts.map +0 -1
- package/dist/workers/brand.invalid.js +0 -19
- package/dist/workers/brand.invalid.js.map +0 -1
- package/dist/workers/brand.js +0 -67
- package/dist/workers/brand.js.map +0 -1
- package/dist/workers/clusterTypes.d.ts +0 -47
- package/dist/workers/clusterTypes.d.ts.map +0 -1
- package/dist/workers/clusterTypes.js +0 -57
- package/dist/workers/clusterTypes.js.map +0 -1
- package/dist/workers/frontendWorker.d.ts +0 -2
- package/dist/workers/frontendWorker.d.ts.map +0 -1
- package/dist/workers/frontendWorker.js +0 -90
- package/dist/workers/frontendWorker.js.map +0 -1
- package/dist/workers/helloWorld.d.ts +0 -2
- package/dist/workers/helloWorld.d.ts.map +0 -1
- package/dist/workers/helloWorld.js +0 -135
- package/dist/workers/helloWorld.js.map +0 -1
- package/dist/workers/matterWorker.d.ts +0 -2
- package/dist/workers/matterWorker.d.ts.map +0 -1
- package/dist/workers/matterWorker.js +0 -104
- package/dist/workers/matterWorker.js.map +0 -1
- package/dist/workers/matterbridgeWorker.d.ts +0 -2
- package/dist/workers/matterbridgeWorker.d.ts.map +0 -1
- package/dist/workers/matterbridgeWorker.js +0 -75
- package/dist/workers/matterbridgeWorker.js.map +0 -1
- package/dist/workers/messageLab.d.ts +0 -134
- package/dist/workers/messageLab.d.ts.map +0 -1
- package/dist/workers/messageLab.js +0 -129
- package/dist/workers/messageLab.js.map +0 -1
- package/dist/workers/testWorker.d.ts +0 -2
- package/dist/workers/testWorker.d.ts.map +0 -1
- package/dist/workers/testWorker.js +0 -45
- package/dist/workers/testWorker.js.map +0 -1
- package/dist/workers/usage.d.ts +0 -19
- package/dist/workers/usage.d.ts.map +0 -1
- package/dist/workers/usage.js +0 -140
- package/dist/workers/usage.js.map +0 -1
- package/dist/workers/workerManager.d.ts +0 -115
- package/dist/workers/workerManager.d.ts.map +0 -1
- package/dist/workers/workerManager.js +0 -464
- package/dist/workers/workerManager.js.map +0 -1
- package/dist/workers/workerServer.d.ts +0 -126
- package/dist/workers/workerServer.d.ts.map +0 -1
- package/dist/workers/workerServer.js +0 -340
- package/dist/workers/workerServer.js.map +0 -1
- package/dist/workers/workerTypes.d.ts +0 -23
- package/dist/workers/workerTypes.d.ts.map +0 -1
- package/dist/workers/workerTypes.js +0 -3
- package/dist/workers/workerTypes.js.map +0 -1
package/dist/matterNode.js
CHANGED
|
@@ -1,35 +1,8 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* This file contains the class MatterNode.
|
|
3
|
-
*
|
|
4
|
-
* @file matterNode.ts
|
|
5
|
-
* @author Luca Liguori
|
|
6
|
-
* @created 2025-10-01
|
|
7
|
-
* @version 1.0.0
|
|
8
|
-
* @license Apache-2.0
|
|
9
|
-
*
|
|
10
|
-
* Copyright 2025, 2026, 2027 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 modules
|
|
25
1
|
import path from 'node:path';
|
|
26
2
|
import fs from 'node:fs';
|
|
27
3
|
import EventEmitter from 'node:events';
|
|
28
|
-
// AnsiLogger module
|
|
29
4
|
import { AnsiLogger, BLUE, CYAN, db, debugStringify, er, nf, or, zb } from 'node-ansi-logger';
|
|
30
|
-
// Node persist manager module
|
|
31
5
|
import { NodeStorageManager } from 'node-persist-manager';
|
|
32
|
-
// @matter
|
|
33
6
|
import '@matter/nodejs';
|
|
34
7
|
import { Logger, LogLevel as MatterLogLevel, LogFormat as MatterLogFormat, StorageService, UINT32_MAX, UINT16_MAX, Environment, } from '@matter/general';
|
|
35
8
|
import { MdnsService } from '@matter/protocol';
|
|
@@ -38,7 +11,6 @@ import { ServerNode, Endpoint } from '@matter/node';
|
|
|
38
11
|
import { AggregatorEndpoint } from '@matter/node/endpoints/aggregator';
|
|
39
12
|
import { BasicInformationServer } from '@matter/node/behaviors/basic-information';
|
|
40
13
|
import { BridgedDeviceBasicInformationServer } from '@matter/node/behaviors/bridged-device-basic-information';
|
|
41
|
-
// Matterbridge
|
|
42
14
|
import { copyDirectory, getIntParameter, getParameter, hasParameter, inspectError, isValidNumber, isValidString, parseVersionString, wait, withTimeout } from '@matterbridge/utils';
|
|
43
15
|
import { dev, MATTER_LOGGER_FILE, MATTER_STORAGE_NAME, plg, NODE_STORAGE_DIR, MATTERBRIDGE_LOGGER_FILE } from '@matterbridge/types';
|
|
44
16
|
import { BroadcastServer } from '@matterbridge/thread';
|
|
@@ -46,48 +18,27 @@ import { bridge } from './matterbridgeDeviceTypes.js';
|
|
|
46
18
|
import { toBaseDevice } from './deviceManager.js';
|
|
47
19
|
import { PluginManager } from './pluginManager.js';
|
|
48
20
|
import { addVirtualDevice } from './helpers.js';
|
|
49
|
-
/**
|
|
50
|
-
* Represents the Matter class.
|
|
51
|
-
*/
|
|
52
21
|
export class MatterNode extends EventEmitter {
|
|
53
22
|
matterbridge;
|
|
54
23
|
pluginName;
|
|
55
24
|
device;
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
/** Matter logger */
|
|
59
|
-
matterLog = new AnsiLogger({ logName: 'MatterNode', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: "debug" /* LogLevel.DEBUG */ });
|
|
60
|
-
/** Matter environment default */
|
|
25
|
+
log = new AnsiLogger({ logName: 'MatterNode', logTimestampFormat: 4, logLevel: "debug" });
|
|
26
|
+
matterLog = new AnsiLogger({ logName: 'MatterNode', logTimestampFormat: 4, logLevel: "debug" });
|
|
61
27
|
environment = Environment.default;
|
|
62
|
-
/** Matter storage id */
|
|
63
28
|
storeId;
|
|
64
|
-
/** Matter mdns service from environment default */
|
|
65
29
|
matterMdnsService;
|
|
66
|
-
/** Matter storage service from environment default */
|
|
67
30
|
matterStorageService;
|
|
68
|
-
/** Matter storage manager created with name 'Matterbridge' */
|
|
69
31
|
matterStorageManager;
|
|
70
|
-
/** Matter storage context created in the storage manager with name 'persist' */
|
|
71
32
|
matterStorageContext;
|
|
72
|
-
/** Matter mdns interface name e.g. 'eth0' or 'wlan0' or 'Wi-Fi' */
|
|
73
33
|
mdnsInterface;
|
|
74
|
-
/** Matter listeningAddressIpv4 address */
|
|
75
34
|
ipv4Address;
|
|
76
|
-
/** Matter listeningAddressIpv6 address */
|
|
77
35
|
ipv6Address;
|
|
78
|
-
/** Matter commissioning port It is incremented in childbridge mode. */
|
|
79
36
|
port;
|
|
80
|
-
/** Matter commissioning passcode. It is incremented in childbridge mode. */
|
|
81
37
|
passcode;
|
|
82
|
-
/** Matter commissioning discriminator. It is incremented in childbridge mode. */
|
|
83
38
|
discriminator;
|
|
84
|
-
/** Matter device certification */
|
|
85
39
|
certification;
|
|
86
|
-
/** Matter server node */
|
|
87
40
|
serverNode;
|
|
88
|
-
/** Matter aggregator node */
|
|
89
41
|
aggregatorNode;
|
|
90
|
-
// Default values for the aggregator node
|
|
91
42
|
aggregatorVendorId = VendorId(getIntParameter('vendorId') ?? 0xfff1);
|
|
92
43
|
aggregatorVendorName = getParameter('vendorName') ?? 'Matterbridge';
|
|
93
44
|
aggregatorProductId = getIntParameter('productId') ?? 0x8000;
|
|
@@ -95,23 +46,12 @@ export class MatterNode extends EventEmitter {
|
|
|
95
46
|
aggregatorDeviceType = DeviceTypeId(getIntParameter('deviceType') ?? bridge.code);
|
|
96
47
|
aggregatorSerialNumber = getParameter('serialNumber');
|
|
97
48
|
aggregatorUniqueId = getParameter('uniqueId');
|
|
98
|
-
/** Advertising nodes map: time advertising started keyed by storeId */
|
|
99
49
|
advertisingNodes = new Map();
|
|
100
|
-
/** Plugins */
|
|
101
50
|
pluginManager;
|
|
102
|
-
/** Dependant MatterNodes keyed by device id */
|
|
103
51
|
dependantMatterNodes = new Map();
|
|
104
|
-
/** Broadcast server */
|
|
105
52
|
server;
|
|
106
53
|
debug = hasParameter('debug') || hasParameter('verbose');
|
|
107
54
|
verbose = hasParameter('verbose');
|
|
108
|
-
/**
|
|
109
|
-
* Creates an instance of the Matter class.
|
|
110
|
-
*
|
|
111
|
-
* @param {SharedMatterbridge} matterbridge - The shared matterbridge instance.
|
|
112
|
-
* @param {PluginName} [pluginName] - The plugin name (optional). If not provided, it is assumed to be the main matter node instance and all plugins are included.
|
|
113
|
-
* @param {MatterbridgeEndpoint} [device] - The matterbridge endpoint device (optional). It is used to create a server mode device.
|
|
114
|
-
*/
|
|
115
55
|
constructor(matterbridge, pluginName, device) {
|
|
116
56
|
super();
|
|
117
57
|
this.matterbridge = matterbridge;
|
|
@@ -120,25 +60,19 @@ export class MatterNode extends EventEmitter {
|
|
|
120
60
|
this.log.logNameColor = '\x1b[38;5;65m';
|
|
121
61
|
if (this.debug)
|
|
122
62
|
this.log.debug(`MatterNode ${this.pluginName ? 'for plugin ' + this.pluginName : 'bridge'} loading...`);
|
|
123
|
-
// Setup Matter parameters
|
|
124
63
|
this.port = matterbridge.port;
|
|
125
64
|
this.passcode = matterbridge.passcode;
|
|
126
65
|
this.discriminator = matterbridge.discriminator;
|
|
127
|
-
// Setup the broadcast server
|
|
128
66
|
this.server = new BroadcastServer('matter', this.log);
|
|
129
67
|
this.server.on('broadcast_message', this.msgHandler.bind(this));
|
|
130
68
|
if (this.verbose)
|
|
131
69
|
this.log.debug(`BroadcastServer is ready`);
|
|
132
|
-
// Ensure the matterbridge directory exists
|
|
133
70
|
fs.mkdirSync(matterbridge.matterbridgeDirectory, { recursive: true });
|
|
134
|
-
// Setup the plugin manager with thread server closed
|
|
135
71
|
this.pluginManager = new PluginManager(this.matterbridge);
|
|
136
|
-
this.pluginManager.logLevel = this.debug ? "debug"
|
|
137
|
-
// @ts-expect-error access private property
|
|
72
|
+
this.pluginManager.logLevel = this.debug ? "debug" : "info";
|
|
138
73
|
this.pluginManager.server.close();
|
|
139
74
|
if (this.verbose)
|
|
140
75
|
this.log.debug(`PluginManager is ready`);
|
|
141
|
-
// Setup the matter environment
|
|
142
76
|
this.environment.vars.set('log.level', MatterLogLevel.DEBUG);
|
|
143
77
|
this.environment.vars.set('log.format', MatterLogFormat.ANSI);
|
|
144
78
|
this.environment.vars.set('path.root', path.join(matterbridge.matterbridgeDirectory, MATTER_STORAGE_NAME));
|
|
@@ -146,18 +80,15 @@ export class MatterNode extends EventEmitter {
|
|
|
146
80
|
this.environment.vars.set('runtime.exitcode', false);
|
|
147
81
|
if (this.verbose)
|
|
148
82
|
this.log.debug(`Matter Environment is ready`);
|
|
149
|
-
// Ensure MdnsService is registered in the default environment
|
|
150
83
|
this.matterMdnsService = new MdnsService(this.environment);
|
|
151
84
|
setImmediate(async () => {
|
|
152
85
|
await this.matterMdnsService?.construction.ready;
|
|
153
86
|
if (this.verbose)
|
|
154
87
|
this.log.debug(`Matter MdnsService is ready`);
|
|
155
88
|
});
|
|
156
|
-
// Setup the matterbridge logger
|
|
157
89
|
if (this.matterbridge.fileLogger) {
|
|
158
90
|
AnsiLogger.setGlobalLogfile(path.join(this.matterbridge.matterbridgeDirectory, MATTERBRIDGE_LOGGER_FILE), this.matterbridge.logLevel);
|
|
159
91
|
}
|
|
160
|
-
// Setup the matter logger
|
|
161
92
|
Logger.destinations.default.write = this.createDestinationMatterLogger();
|
|
162
93
|
const levels = ['debug', 'info', 'notice', 'warn', 'error', 'fatal'];
|
|
163
94
|
if (this.verbose)
|
|
@@ -165,11 +96,6 @@ export class MatterNode extends EventEmitter {
|
|
|
165
96
|
if (this.debug)
|
|
166
97
|
this.log.debug(`MatterNode ${this.pluginName ? 'for plugin ' + this.pluginName : 'bridge'} loaded`);
|
|
167
98
|
}
|
|
168
|
-
/**
|
|
169
|
-
* Handles incoming messages from the broadcast server.
|
|
170
|
-
*
|
|
171
|
-
* @param {WorkerMessage} msg - The incoming message.
|
|
172
|
-
*/
|
|
173
99
|
async msgHandler(msg) {
|
|
174
100
|
if (this.server.isWorkerRequest(msg) && (msg.dst === 'all' || msg.dst === 'matter')) {
|
|
175
101
|
if (this.verbose)
|
|
@@ -200,17 +126,9 @@ export class MatterNode extends EventEmitter {
|
|
|
200
126
|
}
|
|
201
127
|
}
|
|
202
128
|
}
|
|
203
|
-
/**
|
|
204
|
-
* Destroys the Matter instance.
|
|
205
|
-
* It closes the mDNS service and the broadcast server.
|
|
206
|
-
*
|
|
207
|
-
* @param {boolean} closeMdns - Whether to close the mDNS service. Default is true.
|
|
208
|
-
* @returns {Promise<void>} A promise that resolves when the instance is destroyed.
|
|
209
|
-
*/
|
|
210
129
|
async destroy(closeMdns = true) {
|
|
211
130
|
if (this.verbose)
|
|
212
131
|
this.log.debug(`Destroying MatterNode instance for ${this.storeId}...`);
|
|
213
|
-
// Close mDNS service
|
|
214
132
|
if (closeMdns) {
|
|
215
133
|
if (this.verbose)
|
|
216
134
|
this.log.debug(`Closing Matter MdnsService for ${this.storeId}...`);
|
|
@@ -218,31 +136,23 @@ export class MatterNode extends EventEmitter {
|
|
|
218
136
|
if (this.verbose)
|
|
219
137
|
this.log.debug(`Closed Matter MdnsService for ${this.storeId}`);
|
|
220
138
|
}
|
|
221
|
-
// Close the plugin manager
|
|
222
139
|
this.pluginManager.destroy();
|
|
223
|
-
// Close the broadcast server
|
|
224
140
|
this.server.close();
|
|
225
|
-
// Yield to the Node.js event loop to allow all resources to be released
|
|
226
141
|
await this.yieldToNode();
|
|
227
142
|
if (this.verbose)
|
|
228
143
|
this.log.debug(`Destroyed MatterNode instance for ${this.storeId}`);
|
|
229
144
|
}
|
|
230
145
|
async create() {
|
|
231
146
|
this.log.info('Creating Matter node...');
|
|
232
|
-
// Start matter storage
|
|
233
147
|
await this.startMatterStorage();
|
|
234
|
-
// Load plugins from storage
|
|
235
|
-
// @ts-expect-error access private property
|
|
236
148
|
this.pluginManager.matterbridge.nodeStorage = new NodeStorageManager({
|
|
237
149
|
dir: path.join(this.matterbridge.matterbridgeDirectory, NODE_STORAGE_DIR),
|
|
238
150
|
writeQueue: false,
|
|
239
151
|
expiredInterval: undefined,
|
|
240
152
|
logging: false,
|
|
241
153
|
});
|
|
242
|
-
// @ts-expect-error access private property
|
|
243
154
|
this.pluginManager.matterbridge.nodeContext = await this.pluginManager.matterbridge.nodeStorage.createStorage('matterbridge');
|
|
244
155
|
await this.pluginManager.loadFromStorage();
|
|
245
|
-
// Create Matter node for a server mode device
|
|
246
156
|
if (this.pluginName && this.device && this.device.deviceName) {
|
|
247
157
|
this.log.debug(`Creating MatterNode instance for server node device ${CYAN}${this.device.deviceName}${db}...`);
|
|
248
158
|
await this.createDeviceServerNode(this.pluginName, this.device);
|
|
@@ -253,7 +163,6 @@ export class MatterNode extends EventEmitter {
|
|
|
253
163
|
if (!this.pluginName) {
|
|
254
164
|
this.log.debug('Creating MatterNode instance for all plugins...');
|
|
255
165
|
await this.createMatterbridgeServerNode();
|
|
256
|
-
// Load all enabled plugins
|
|
257
166
|
this.log.debug('Loading all plugins...');
|
|
258
167
|
const loadPromises = [];
|
|
259
168
|
for (const plugin of this.pluginManager.array().filter((p) => p.enabled)) {
|
|
@@ -266,7 +175,6 @@ export class MatterNode extends EventEmitter {
|
|
|
266
175
|
}
|
|
267
176
|
else {
|
|
268
177
|
this.log.debug(`Creating MatterNode instance for plugin ${CYAN}${this.pluginName}${db}...`);
|
|
269
|
-
// Load only the specified plugin
|
|
270
178
|
this.log.debug(`Loading plugin ${CYAN}${this.pluginName}${db}...`);
|
|
271
179
|
await this.pluginManager.load(this.pluginName);
|
|
272
180
|
this.log.debug(`Loaded plugin ${CYAN}${this.pluginName}${db}`);
|
|
@@ -280,16 +188,13 @@ export class MatterNode extends EventEmitter {
|
|
|
280
188
|
if (!this.serverNode && !this.pluginName)
|
|
281
189
|
throw new Error('Matter server node not created yet. Call create() first.');
|
|
282
190
|
this.log.info('Starting MatterNode...');
|
|
283
|
-
// Start Matter node for a server mode device
|
|
284
191
|
if (this.pluginName && this.device && this.device.deviceName) {
|
|
285
|
-
// Start the server node
|
|
286
192
|
this.log.debug(`Starting MatterNode for server device ${this.pluginName}:${this.device.deviceName}...`);
|
|
287
193
|
await this.startServerNode();
|
|
288
194
|
this.log.debug(`Started MatterNode for server device ${this.pluginName}:${this.device.deviceName}`);
|
|
289
195
|
return;
|
|
290
196
|
}
|
|
291
197
|
if (!this.pluginName) {
|
|
292
|
-
// Start all loaded plugins
|
|
293
198
|
this.log.debug('Starting all plugins...');
|
|
294
199
|
const startPromises = [];
|
|
295
200
|
for (const plugin of this.pluginManager.array().filter((p) => p.enabled && p.loaded)) {
|
|
@@ -297,11 +202,9 @@ export class MatterNode extends EventEmitter {
|
|
|
297
202
|
}
|
|
298
203
|
await Promise.all(startPromises);
|
|
299
204
|
this.log.debug('Started all plugins');
|
|
300
|
-
// Start the server node
|
|
301
205
|
this.log.debug('Starting MatterNode for all plugins...');
|
|
302
206
|
await this.startServerNode();
|
|
303
207
|
this.log.debug('Started MatterNode for all plugins');
|
|
304
|
-
// Configure all loaded plugins
|
|
305
208
|
this.log.debug('Configuring all plugins...');
|
|
306
209
|
const configurePromises = [];
|
|
307
210
|
for (const plugin of this.pluginManager.array().filter((p) => p.enabled && p.started)) {
|
|
@@ -311,16 +214,12 @@ export class MatterNode extends EventEmitter {
|
|
|
311
214
|
this.log.debug('Configured all plugins');
|
|
312
215
|
}
|
|
313
216
|
else {
|
|
314
|
-
// Start the loaded plugin
|
|
315
217
|
await this.pluginManager.start(this.pluginName, 'Starting MatterNode');
|
|
316
|
-
// Start the server node
|
|
317
218
|
this.log.debug(`Starting MatterNode for plugin ${this.pluginName}...`);
|
|
318
219
|
await this.startServerNode();
|
|
319
220
|
this.log.debug(`Started MatterNode for plugin ${this.pluginName}`);
|
|
320
|
-
// Configure the plugin
|
|
321
221
|
await this.pluginManager.configure(this.pluginName);
|
|
322
222
|
}
|
|
323
|
-
// Start the dependant MatterNodes
|
|
324
223
|
this.log.debug(`Starting dependant MatterNodes...`);
|
|
325
224
|
for (const dependantMatterNode of this.dependantMatterNodes.values()) {
|
|
326
225
|
await dependantMatterNode.start();
|
|
@@ -333,15 +232,13 @@ export class MatterNode extends EventEmitter {
|
|
|
333
232
|
if (!this.serverNode)
|
|
334
233
|
throw new Error('Matter server node not created yet. Call create() first.');
|
|
335
234
|
this.log.info('Stopping MatterNode...');
|
|
336
|
-
// Stop Matter node for a server mode device
|
|
337
235
|
if (this.pluginName && this.device && this.device.deviceName) {
|
|
338
|
-
// Stop the server node
|
|
339
236
|
this.log.debug(`Stopping MatterNode for server device ${this.pluginName}:${this.device.deviceName}...`);
|
|
340
237
|
await this.stopServerNode();
|
|
341
238
|
this.serverNode = undefined;
|
|
342
239
|
this.aggregatorNode = undefined;
|
|
343
240
|
await this.stopMatterStorage();
|
|
344
|
-
await this.destroy(false);
|
|
241
|
+
await this.destroy(false);
|
|
345
242
|
this.log.debug(`Stopped MatterNode for server device ${this.pluginName}:${this.device.deviceName}`);
|
|
346
243
|
this.log.info('Stopped MatterNode');
|
|
347
244
|
await this.yieldToNode();
|
|
@@ -361,7 +258,6 @@ export class MatterNode extends EventEmitter {
|
|
|
361
258
|
await this.pluginManager.shutdown(this.pluginName, 'Stopping MatterNode');
|
|
362
259
|
this.log.debug(`Stopped plugin ${this.pluginName}`);
|
|
363
260
|
}
|
|
364
|
-
// Stop the dependant MatterNodes
|
|
365
261
|
this.log.debug(`Stopping dependant MatterNodes...`);
|
|
366
262
|
for (const dependantMatterNode of this.dependantMatterNodes.values()) {
|
|
367
263
|
await dependantMatterNode.stop();
|
|
@@ -374,46 +270,24 @@ export class MatterNode extends EventEmitter {
|
|
|
374
270
|
this.log.info('Stopped MatterNode');
|
|
375
271
|
await this.yieldToNode();
|
|
376
272
|
}
|
|
377
|
-
/**
|
|
378
|
-
* Creates a MatterLogger function to show the matter.js log messages in AnsiLogger (console and frontend).
|
|
379
|
-
* It also logs to file (matter.log) if fileLogger is true.
|
|
380
|
-
*
|
|
381
|
-
* @returns {(text: string, message: Diagnostic.Message) => void} The MatterLogger function to be used in Logger.destinations.default.write.
|
|
382
|
-
*/
|
|
383
273
|
createDestinationMatterLogger() {
|
|
384
|
-
this.matterLog.logNameColor = '\x1b[34m';
|
|
274
|
+
this.matterLog.logNameColor = '\x1b[34m';
|
|
385
275
|
if (this.matterbridge.matterFileLogger) {
|
|
386
276
|
this.matterLog.logFilePath = path.join(this.matterbridge.matterbridgeDirectory, MATTER_LOGGER_FILE);
|
|
387
277
|
}
|
|
388
278
|
return (text, message) => {
|
|
389
|
-
// 2024-08-21 08:55:19.488 DEBUG InteractionMessenger Sending DataReport chunk with 28 attributes and 0 events: 1004 bytes
|
|
390
279
|
const logger = text.slice(44, 44 + 20).trim();
|
|
391
280
|
const msg = text.slice(65);
|
|
392
281
|
this.matterLog.logName = logger;
|
|
393
282
|
this.matterLog.log(MatterLogLevel.names[message.level], msg);
|
|
394
283
|
};
|
|
395
284
|
}
|
|
396
|
-
/**
|
|
397
|
-
* Starts the matter storage with name Matterbridge and performs a backup.
|
|
398
|
-
*
|
|
399
|
-
* @returns {Promise<void>} - A promise that resolves when the storage is started.
|
|
400
|
-
*/
|
|
401
285
|
async startMatterStorage() {
|
|
402
|
-
// Setup Matter storage
|
|
403
286
|
this.log.info(`Starting matter node storage...`);
|
|
404
287
|
this.matterStorageService = this.environment.get(StorageService);
|
|
405
288
|
this.log.info(`Started matter node storage in ${CYAN}${this.matterStorageService.location}${nf}`);
|
|
406
|
-
// Backup matter storage since it is created/opened correctly
|
|
407
289
|
await this.backupMatterStorage(path.join(this.matterbridge.matterbridgeDirectory, MATTER_STORAGE_NAME), path.join(this.matterbridge.matterbridgeDirectory, MATTER_STORAGE_NAME + '.backup'));
|
|
408
290
|
}
|
|
409
|
-
/**
|
|
410
|
-
* Makes a backup copy of the specified matter storage directory.
|
|
411
|
-
*
|
|
412
|
-
* @param {string} storageName - The name of the storage directory to be backed up.
|
|
413
|
-
* @param {string} backupName - The name of the backup directory to be created.
|
|
414
|
-
* @private
|
|
415
|
-
* @returns {Promise<void>} A promise that resolves when the has been done.
|
|
416
|
-
*/
|
|
417
291
|
async backupMatterStorage(storageName, backupName) {
|
|
418
292
|
this.log.info(`Creating matter node storage backup from ${CYAN}${storageName}${nf} to ${CYAN}${backupName}${nf}...`);
|
|
419
293
|
try {
|
|
@@ -421,7 +295,6 @@ export class MatterNode extends EventEmitter {
|
|
|
421
295
|
this.log.info('Created matter node storage backup');
|
|
422
296
|
}
|
|
423
297
|
catch (error) {
|
|
424
|
-
// istanbul ignore next if
|
|
425
298
|
if (error instanceof Error && error?.code === 'ENOENT') {
|
|
426
299
|
this.log.info(`No matter node storage found to backup from ${CYAN}${storageName}${nf} to ${CYAN}${backupName}${nf}`);
|
|
427
300
|
}
|
|
@@ -430,11 +303,6 @@ export class MatterNode extends EventEmitter {
|
|
|
430
303
|
}
|
|
431
304
|
}
|
|
432
305
|
}
|
|
433
|
-
/**
|
|
434
|
-
* Stops the matter storage.
|
|
435
|
-
*
|
|
436
|
-
* @returns {Promise<void>} A promise that resolves when the storage is stopped.
|
|
437
|
-
*/
|
|
438
306
|
async stopMatterStorage() {
|
|
439
307
|
this.log.info('Closing matter node storage...');
|
|
440
308
|
await this.matterStorageManager?.close();
|
|
@@ -444,21 +312,6 @@ export class MatterNode extends EventEmitter {
|
|
|
444
312
|
this.log.info('Closed matter node storage');
|
|
445
313
|
this.emit('closed');
|
|
446
314
|
}
|
|
447
|
-
/**
|
|
448
|
-
* Creates a server node storage context.
|
|
449
|
-
*
|
|
450
|
-
* @param {string} storeId - The storeId.
|
|
451
|
-
* @param {string} deviceName - The name of the device.
|
|
452
|
-
* @param {DeviceTypeId} deviceType - The device type of the device.
|
|
453
|
-
* @param {VendorId} vendorId - The vendor ID.
|
|
454
|
-
* @param {string} vendorName - The vendor name.
|
|
455
|
-
* @param {number} productId - The product ID.
|
|
456
|
-
* @param {string} productName - The product name.
|
|
457
|
-
* @param {string} [serialNumber] - The serial number of the device (optional).
|
|
458
|
-
* @param {string} [uniqueId] - The unique ID of the device (optional).
|
|
459
|
-
* @returns {Promise<StorageContext>} The storage context for the commissioning server.
|
|
460
|
-
* @throws {Error} If the storage service is not initialized.
|
|
461
|
-
*/
|
|
462
315
|
async createServerNodeContext(storeId, deviceName, deviceType, vendorId, vendorName, productId, productName, serialNumber, uniqueId) {
|
|
463
316
|
if (!this.matterStorageService) {
|
|
464
317
|
throw new Error('No storage service initialized');
|
|
@@ -501,52 +354,33 @@ export class MatterNode extends EventEmitter {
|
|
|
501
354
|
this.log.debug(`- hardwareVersionString: ${await storageContext.get('hardwareVersionString')}`);
|
|
502
355
|
return storageContext;
|
|
503
356
|
}
|
|
504
|
-
/**
|
|
505
|
-
* Creates a server node.
|
|
506
|
-
*
|
|
507
|
-
* @param {number} [port] - The port number for the server node. Defaults to 5540.
|
|
508
|
-
* @param {number} [passcode] - The passcode for the server node. Defaults to 20242025.
|
|
509
|
-
* @param {number} [discriminator] - The discriminator for the server node. Defaults to 3850.
|
|
510
|
-
* @returns {Promise<ServerNode<ServerNode.RootEndpoint>>} A promise that resolves to the created server node.
|
|
511
|
-
* @throws {Error} If the matter storage context is not created yet.
|
|
512
|
-
*/
|
|
513
357
|
async createServerNode(port = 5540, passcode = 20252026, discriminator = 3850) {
|
|
514
358
|
if (!this.matterStorageContext) {
|
|
515
359
|
throw new Error('Matter server node context not created yet. Call createServerNodeContext() first.');
|
|
516
360
|
}
|
|
517
361
|
const storeId = await this.matterStorageContext.get('storeId');
|
|
518
362
|
this.log.notice(`Creating server node for ${storeId} on port ${port} with passcode ${passcode} and discriminator ${discriminator}...`);
|
|
519
|
-
/**
|
|
520
|
-
* Create a Matter ServerNode, which contains the Root Endpoint and all relevant data and configuration
|
|
521
|
-
*/
|
|
522
363
|
const serverNode = await ServerNode.create({
|
|
523
|
-
// Required: Give the Node a unique ID which is used to store the state of this node
|
|
524
364
|
id: storeId,
|
|
525
|
-
// Provide the environment to run this node in
|
|
526
365
|
environment: this.environment,
|
|
527
|
-
// Provide Network relevant configuration like the port
|
|
528
366
|
network: {
|
|
529
367
|
listeningAddressIpv4: this.ipv4Address,
|
|
530
368
|
listeningAddressIpv6: this.ipv6Address,
|
|
531
369
|
port,
|
|
532
370
|
},
|
|
533
|
-
// Provide the certificate for the device
|
|
534
371
|
operationalCredentials: {
|
|
535
372
|
certification: this.certification,
|
|
536
373
|
},
|
|
537
|
-
// Provide Commissioning relevant settings
|
|
538
374
|
commissioning: {
|
|
539
375
|
passcode,
|
|
540
376
|
discriminator,
|
|
541
377
|
},
|
|
542
|
-
// Provide Node announcement settings
|
|
543
378
|
productDescription: {
|
|
544
379
|
name: await this.matterStorageContext.get('deviceName'),
|
|
545
380
|
deviceType: DeviceTypeId(await this.matterStorageContext.get('deviceType')),
|
|
546
381
|
vendorId: VendorId(await this.matterStorageContext.get('vendorId')),
|
|
547
382
|
productId: await this.matterStorageContext.get('productId'),
|
|
548
383
|
},
|
|
549
|
-
// Provide defaults for the BasicInformation cluster on the Root endpoint
|
|
550
384
|
basicInformation: {
|
|
551
385
|
vendorId: VendorId(await this.matterStorageContext.get('vendorId')),
|
|
552
386
|
vendorName: await this.matterStorageContext.get('vendorName'),
|
|
@@ -563,23 +397,17 @@ export class MatterNode extends EventEmitter {
|
|
|
563
397
|
reachable: true,
|
|
564
398
|
},
|
|
565
399
|
});
|
|
566
|
-
/**
|
|
567
|
-
* This event is triggered when the device is initially commissioned successfully.
|
|
568
|
-
* This means: It is added to the first fabric.
|
|
569
|
-
*/
|
|
570
400
|
serverNode.lifecycle.commissioned.on(() => {
|
|
571
401
|
this.log.notice(`Server node for ${storeId} was initially commissioned successfully!`);
|
|
572
402
|
this.advertisingNodes.delete(storeId);
|
|
573
403
|
this.server.request({ type: 'frontend_refreshrequired', src: 'matter', dst: 'frontend', params: { changed: 'matter', matter: { ...this.getServerNodeData(serverNode) } } });
|
|
574
404
|
});
|
|
575
|
-
/** This event is triggered when all fabrics are removed from the device, usually it also does a factory reset then. */
|
|
576
405
|
serverNode.lifecycle.decommissioned.on(() => {
|
|
577
406
|
this.log.notice(`Server node for ${storeId} was fully decommissioned successfully!`);
|
|
578
407
|
this.advertisingNodes.delete(storeId);
|
|
579
408
|
this.server.request({ type: 'frontend_refreshrequired', src: 'matter', dst: 'frontend', params: { changed: 'matter', matter: { ...this.getServerNodeData(serverNode) } } });
|
|
580
409
|
this.server.request({ type: 'frontend_snackbarmessage', src: 'matter', dst: 'frontend', params: { message: `${storeId} is offline`, timeout: 5, severity: 'warning' } });
|
|
581
410
|
});
|
|
582
|
-
/** This event is triggered when the device went online. This means that it is discoverable in the network. */
|
|
583
411
|
serverNode.lifecycle.online.on(async () => {
|
|
584
412
|
this.log.notice(`Server node for ${storeId} is online`);
|
|
585
413
|
if (!serverNode.lifecycle.isCommissioned) {
|
|
@@ -597,7 +425,6 @@ export class MatterNode extends EventEmitter {
|
|
|
597
425
|
this.server.request({ type: 'frontend_snackbarmessage', src: 'matter', dst: 'frontend', params: { message: `${storeId} is online`, timeout: 5, severity: 'success' } });
|
|
598
426
|
this.emit('online', storeId);
|
|
599
427
|
});
|
|
600
|
-
/** This event is triggered when the device went offline. it is not longer discoverable or connectable in the network. */
|
|
601
428
|
serverNode.lifecycle.offline.on(() => {
|
|
602
429
|
this.log.notice(`Server node for ${storeId} is offline`);
|
|
603
430
|
this.advertisingNodes.delete(storeId);
|
|
@@ -605,15 +432,11 @@ export class MatterNode extends EventEmitter {
|
|
|
605
432
|
this.server.request({ type: 'frontend_snackbarmessage', src: 'matter', dst: 'frontend', params: { message: `${storeId} is offline`, timeout: 5, severity: 'warning' } });
|
|
606
433
|
this.emit('offline', storeId);
|
|
607
434
|
});
|
|
608
|
-
/**
|
|
609
|
-
* This event is triggered when a fabric is added, removed or updated on the device. Use this if more granular
|
|
610
|
-
* information is needed.
|
|
611
|
-
*/
|
|
612
435
|
serverNode.events.commissioning.fabricsChanged.on((fabricIndex, fabricAction) => {
|
|
613
436
|
let action = '';
|
|
614
437
|
switch (fabricAction) {
|
|
615
438
|
case 'added':
|
|
616
|
-
this.advertisingNodes.delete(storeId);
|
|
439
|
+
this.advertisingNodes.delete(storeId);
|
|
617
440
|
action = 'added';
|
|
618
441
|
break;
|
|
619
442
|
case 'deleted':
|
|
@@ -626,22 +449,14 @@ export class MatterNode extends EventEmitter {
|
|
|
626
449
|
this.log.notice(`Commissioned fabric index ${fabricIndex} ${action} on server node for ${storeId}: ${debugStringify(serverNode.state.commissioning.fabrics[fabricIndex])}`);
|
|
627
450
|
this.server.request({ type: 'frontend_refreshrequired', src: 'matter', dst: 'frontend', params: { changed: 'matter', matter: { ...this.getServerNodeData(serverNode) } } });
|
|
628
451
|
});
|
|
629
|
-
/**
|
|
630
|
-
* This event is triggered when an operative new session was opened by a Controller.
|
|
631
|
-
* It is not triggered for the initial commissioning process, just afterwards for real connections.
|
|
632
|
-
*/
|
|
633
452
|
serverNode.events.sessions.opened.on((session) => {
|
|
634
453
|
this.log.notice(`Session opened on server node for ${storeId}: ${debugStringify(session)}`);
|
|
635
454
|
this.server.request({ type: 'frontend_refreshrequired', src: 'matter', dst: 'frontend', params: { changed: 'matter', matter: { ...this.getServerNodeData(serverNode) } } });
|
|
636
455
|
});
|
|
637
|
-
/**
|
|
638
|
-
* This event is triggered when an operative session is closed by a Controller or because the Device goes offline.
|
|
639
|
-
*/
|
|
640
456
|
serverNode.events.sessions.closed.on((session) => {
|
|
641
457
|
this.log.notice(`Session closed on server node for ${storeId}: ${debugStringify(session)}`);
|
|
642
458
|
this.server.request({ type: 'frontend_refreshrequired', src: 'matter', dst: 'frontend', params: { changed: 'matter', matter: { ...this.getServerNodeData(serverNode) } } });
|
|
643
459
|
});
|
|
644
|
-
/** This event is triggered when a subscription gets added or removed on an operative session. */
|
|
645
460
|
serverNode.events.sessions.subscriptionsChanged.on((session) => {
|
|
646
461
|
this.log.notice(`Session subscriptions changed on server node for ${storeId}: ${debugStringify(session)}`);
|
|
647
462
|
this.server.request({ type: 'frontend_refreshrequired', src: 'matter', dst: 'frontend', params: { changed: 'matter', matter: { ...this.getServerNodeData(serverNode) } } });
|
|
@@ -650,12 +465,6 @@ export class MatterNode extends EventEmitter {
|
|
|
650
465
|
this.log.info(`Created server node for ${this.storeId}`);
|
|
651
466
|
return serverNode;
|
|
652
467
|
}
|
|
653
|
-
/**
|
|
654
|
-
* Gets the matter serializable data of the specified server node.
|
|
655
|
-
*
|
|
656
|
-
* @param {ServerNode} [serverNode] - The server node to start.
|
|
657
|
-
* @returns {ApiMatter} The serializable data of the server node.
|
|
658
|
-
*/
|
|
659
468
|
getServerNodeData(serverNode) {
|
|
660
469
|
const advertiseTime = this.advertisingNodes.get(serverNode.id) || 0;
|
|
661
470
|
return {
|
|
@@ -672,13 +481,6 @@ export class MatterNode extends EventEmitter {
|
|
|
672
481
|
serialNumber: serverNode.state.basicInformation.serialNumber,
|
|
673
482
|
};
|
|
674
483
|
}
|
|
675
|
-
/**
|
|
676
|
-
* Starts the specified server node.
|
|
677
|
-
*
|
|
678
|
-
* @param {number} [timeout] - The timeout in milliseconds for starting the server node. Defaults to 30 seconds.
|
|
679
|
-
* @returns {Promise<void>} A promise that resolves when the server node has started.
|
|
680
|
-
* @throws {Error} If the server node is not created yet.
|
|
681
|
-
*/
|
|
682
484
|
async startServerNode(timeout = 30000) {
|
|
683
485
|
if (!this.serverNode) {
|
|
684
486
|
throw new Error('Matter server node not created yet. Call create() first.');
|
|
@@ -689,17 +491,9 @@ export class MatterNode extends EventEmitter {
|
|
|
689
491
|
this.log.notice(`Started ${this.serverNode.id} server node`);
|
|
690
492
|
}
|
|
691
493
|
catch (error) {
|
|
692
|
-
// istanbul ignore next
|
|
693
494
|
this.log.error(`Failed to start ${this.serverNode.id} server node: ${error instanceof Error ? error.message : error}`);
|
|
694
495
|
}
|
|
695
496
|
}
|
|
696
|
-
/**
|
|
697
|
-
* Stops the specified server node.
|
|
698
|
-
*
|
|
699
|
-
* @param {number} [timeout] - The timeout in milliseconds for stopping the server node. Defaults to 30 seconds.
|
|
700
|
-
* @returns {Promise<void>} A promise that resolves when the server node has stopped.
|
|
701
|
-
* @throws {Error} If the server node is not created yet.
|
|
702
|
-
*/
|
|
703
497
|
async stopServerNode(timeout = 30000) {
|
|
704
498
|
if (!this.serverNode) {
|
|
705
499
|
throw new Error('Matter server node not created yet. Call create() first.');
|
|
@@ -710,16 +504,9 @@ export class MatterNode extends EventEmitter {
|
|
|
710
504
|
this.log.info(`Closed ${this.serverNode.id} server node`);
|
|
711
505
|
}
|
|
712
506
|
catch (error) {
|
|
713
|
-
// istanbul ignore next
|
|
714
507
|
this.log.error(`Failed to close ${this.serverNode.id} server node: ${error instanceof Error ? error.message : error}`);
|
|
715
508
|
}
|
|
716
509
|
}
|
|
717
|
-
/**
|
|
718
|
-
* Creates an aggregator node with the specified storage context.
|
|
719
|
-
*
|
|
720
|
-
* @returns {Promise<Endpoint<AggregatorEndpoint>>} A promise that resolves to the created aggregator node.
|
|
721
|
-
* @throws {Error} If the matter storage context is not created yet.
|
|
722
|
-
*/
|
|
723
510
|
async createAggregatorNode() {
|
|
724
511
|
if (!this.matterStorageContext) {
|
|
725
512
|
throw new Error('Matter server node context not created yet. Call createServerNodeContext() first.');
|
|
@@ -729,16 +516,9 @@ export class MatterNode extends EventEmitter {
|
|
|
729
516
|
this.log.info(`Created ${await this.matterStorageContext.get('storeId')} aggregator`);
|
|
730
517
|
return aggregatorNode;
|
|
731
518
|
}
|
|
732
|
-
/**
|
|
733
|
-
* Creates the matterbridge server node.
|
|
734
|
-
*
|
|
735
|
-
* @returns {Promise<ServerNode<ServerNode.RootEndpoint>>} A promise that resolves to the created matterbridge server node.
|
|
736
|
-
*/
|
|
737
519
|
async createMatterbridgeServerNode() {
|
|
738
520
|
this.log.debug(`Creating ${plg}Matterbridge${db} server node...`);
|
|
739
|
-
this.matterStorageContext = await this.createServerNodeContext('Matterbridge',
|
|
740
|
-
'Matterbridge', // deviceName
|
|
741
|
-
this.aggregatorDeviceType, this.aggregatorVendorId, this.aggregatorVendorName, this.aggregatorProductId, this.aggregatorProductName, this.aggregatorSerialNumber, this.aggregatorUniqueId);
|
|
521
|
+
this.matterStorageContext = await this.createServerNodeContext('Matterbridge', 'Matterbridge', this.aggregatorDeviceType, this.aggregatorVendorId, this.aggregatorVendorName, this.aggregatorProductId, this.aggregatorProductName, this.aggregatorSerialNumber, this.aggregatorUniqueId);
|
|
742
522
|
this.serverNode = await this.createServerNode(this.port ? this.port++ : undefined, this.passcode ? this.passcode++ : undefined, this.discriminator ? this.discriminator++ : undefined);
|
|
743
523
|
this.aggregatorNode = await this.createAggregatorNode();
|
|
744
524
|
this.log.debug(`Adding ${plg}Matterbridge${db} aggregator node...`);
|
|
@@ -749,13 +529,6 @@ export class MatterNode extends EventEmitter {
|
|
|
749
529
|
this.log.debug(`Created ${plg}Matterbridge${db} server node`);
|
|
750
530
|
return this.serverNode;
|
|
751
531
|
}
|
|
752
|
-
/**
|
|
753
|
-
* Creates and configures the server node for an accessory plugin for a given device.
|
|
754
|
-
*
|
|
755
|
-
* @param {Plugin | PluginName} plugin - The plugin to configure.
|
|
756
|
-
* @param {MatterbridgeEndpoint} device - The device to associate with the plugin.
|
|
757
|
-
* @returns {Promise<ServerNode<ServerNode.RootEndpoint> | undefined>} A promise that resolves to the server node for the accessory plugin.
|
|
758
|
-
*/
|
|
759
532
|
async createAccessoryPlugin(plugin, device) {
|
|
760
533
|
if (typeof plugin === 'string') {
|
|
761
534
|
const _plugin = this.pluginManager.get(plugin);
|
|
@@ -777,12 +550,6 @@ export class MatterNode extends EventEmitter {
|
|
|
777
550
|
}
|
|
778
551
|
return this.serverNode;
|
|
779
552
|
}
|
|
780
|
-
/**
|
|
781
|
-
* Creates and configures the server node and the aggregator node for a dynamic plugin.
|
|
782
|
-
*
|
|
783
|
-
* @param {Plugin | PluginName} plugin - The plugin to configure.
|
|
784
|
-
* @returns {Promise<ServerNode<ServerNode.RootEndpoint> | undefined>} A promise that resolves to the server node for the dynamic plugin.
|
|
785
|
-
*/
|
|
786
553
|
async createDynamicPlugin(plugin) {
|
|
787
554
|
if (typeof plugin === 'string') {
|
|
788
555
|
const _plugin = this.pluginManager.get(plugin);
|
|
@@ -806,13 +573,6 @@ export class MatterNode extends EventEmitter {
|
|
|
806
573
|
}
|
|
807
574
|
return this.serverNode;
|
|
808
575
|
}
|
|
809
|
-
/**
|
|
810
|
-
* Creates and configures the server node for a single not bridged device.
|
|
811
|
-
*
|
|
812
|
-
* @param {Plugin | PluginName} plugin - The plugin to configure.
|
|
813
|
-
* @param {MatterbridgeEndpoint} device - The device to associate with the plugin.
|
|
814
|
-
* @returns {Promise<ServerNode<ServerNode.RootEndpoint> | undefined>} A promise that resolves to the server node for the device with mode server.
|
|
815
|
-
*/
|
|
816
576
|
async createDeviceServerNode(plugin, device) {
|
|
817
577
|
if (typeof plugin === 'string') {
|
|
818
578
|
const _plugin = this.pluginManager.get(plugin);
|
|
@@ -833,22 +593,13 @@ export class MatterNode extends EventEmitter {
|
|
|
833
593
|
}
|
|
834
594
|
return this.serverNode;
|
|
835
595
|
}
|
|
836
|
-
/**
|
|
837
|
-
* Adds a MatterbridgeEndpoint to the specified plugin.
|
|
838
|
-
*
|
|
839
|
-
* @param {string} pluginName - The name of the plugin.
|
|
840
|
-
* @param {MatterbridgeEndpoint} device - The device to add as a bridged endpoint.
|
|
841
|
-
* @returns {Promise<MatterbridgeEndpoint | undefined>} A promise that resolves to the added bridged endpoint, or undefined if there was an error.
|
|
842
|
-
*/
|
|
843
596
|
async addBridgedEndpoint(pluginName, device) {
|
|
844
|
-
// Check if the plugin is registered
|
|
845
597
|
const plugin = this.pluginManager.get(pluginName);
|
|
846
598
|
if (!plugin)
|
|
847
599
|
throw new Error(`Error adding bridged endpoint ${plg}${pluginName}${er}:${dev}${device.deviceName}${er} (${zb}${device.name}${er}): plugin not found`);
|
|
848
600
|
if (device.mode === 'server') {
|
|
849
601
|
try {
|
|
850
602
|
this.log.debug(`Creating MatterNode for device ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} (${zb}${device.name}${db})...`);
|
|
851
|
-
// Create the MatterNode to manage the device
|
|
852
603
|
const matterNode = new MatterNode(this.matterbridge, pluginName, device);
|
|
853
604
|
matterNode.port = this.port ? this.port++ : undefined;
|
|
854
605
|
matterNode.passcode = this.passcode ? this.passcode++ : undefined;
|
|
@@ -864,7 +615,6 @@ export class MatterNode extends EventEmitter {
|
|
|
864
615
|
}
|
|
865
616
|
else if (this.matterbridge.bridgeMode === 'bridge') {
|
|
866
617
|
if (device.mode === 'matter') {
|
|
867
|
-
// Register and add the device to the Matter server node
|
|
868
618
|
this.log.debug(`Adding matter endpoint ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} (${zb}${device.name}${db})...`);
|
|
869
619
|
if (!this.serverNode)
|
|
870
620
|
throw new Error(`Server node not found for matter endpoint ${plg}${pluginName}${er}:${dev}${device.deviceName}${er} (${zb}${device.name}${er})`);
|
|
@@ -877,7 +627,6 @@ export class MatterNode extends EventEmitter {
|
|
|
877
627
|
}
|
|
878
628
|
}
|
|
879
629
|
else {
|
|
880
|
-
// Register and add the device to the Matter aggregator node
|
|
881
630
|
this.log.debug(`Adding bridged endpoint ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} (${zb}${device.name}${db})...`);
|
|
882
631
|
if (!this.aggregatorNode)
|
|
883
632
|
throw new Error(`Aggregator node not found for endpoint ${plg}${pluginName}${er}:${dev}${device.deviceName}${er} (${zb}${device.name}${er})`);
|
|
@@ -891,7 +640,6 @@ export class MatterNode extends EventEmitter {
|
|
|
891
640
|
}
|
|
892
641
|
}
|
|
893
642
|
else if (this.matterbridge.bridgeMode === 'childbridge') {
|
|
894
|
-
// Register and add the device to the plugin server node
|
|
895
643
|
if (plugin.type === 'AccessoryPlatform') {
|
|
896
644
|
try {
|
|
897
645
|
this.log.debug(`Adding accessory endpoint ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} (${zb}${device.name}${db})...`);
|
|
@@ -907,12 +655,10 @@ export class MatterNode extends EventEmitter {
|
|
|
907
655
|
return;
|
|
908
656
|
}
|
|
909
657
|
}
|
|
910
|
-
// Register and add the device to the plugin aggregator node
|
|
911
658
|
if (plugin.type === 'DynamicPlatform') {
|
|
912
659
|
try {
|
|
913
660
|
this.log.debug(`Adding bridged endpoint ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} (${zb}${device.name}${db})...`);
|
|
914
661
|
if (!this.serverNode) {
|
|
915
|
-
// Fast plugins can add another device before the server node is ready, so we wait for the server node to be ready
|
|
916
662
|
await this.createDynamicPlugin(plugin);
|
|
917
663
|
}
|
|
918
664
|
if (device.mode === 'matter')
|
|
@@ -928,30 +674,19 @@ export class MatterNode extends EventEmitter {
|
|
|
928
674
|
}
|
|
929
675
|
if (plugin.registeredDevices !== undefined)
|
|
930
676
|
plugin.registeredDevices++;
|
|
931
|
-
// Add the device to the DeviceManager
|
|
932
677
|
await device.construction.ready;
|
|
933
678
|
await this.server.fetch({ type: 'devices_set', src: this.server.name, dst: 'devices', params: { device: toBaseDevice(device) } });
|
|
934
|
-
// Subscribe to the attributes changed event
|
|
935
679
|
await this.subscribeAttributeChanged(plugin, device);
|
|
936
680
|
this.log.info(`Added endpoint #${plugin.registeredDevices} ${plg}${pluginName}${nf}:${dev}${device.deviceName}${nf} (${zb}${device.name}${nf})`);
|
|
937
681
|
await this.yieldToNode(10);
|
|
938
682
|
return device;
|
|
939
683
|
}
|
|
940
|
-
/**
|
|
941
|
-
* Removes a MatterbridgeEndpoint from the specified plugin.
|
|
942
|
-
*
|
|
943
|
-
* @param {string} pluginName - The name of the plugin.
|
|
944
|
-
* @param {MatterbridgeEndpoint} device - The device to remove as a bridged endpoint.
|
|
945
|
-
* @returns {Promise<MatterbridgeEndpoint | undefined>} A promise that resolves to the removed bridged endpoint, or undefined if there was an error.
|
|
946
|
-
*/
|
|
947
684
|
async removeBridgedEndpoint(pluginName, device) {
|
|
948
685
|
this.log.debug(`Removing bridged endpoint ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} (${zb}${device.name}${db})...`);
|
|
949
|
-
// Check if the plugin is registered
|
|
950
686
|
const plugin = this.pluginManager.get(pluginName);
|
|
951
687
|
if (!plugin)
|
|
952
688
|
throw new Error(`Error removing bridged endpoint ${plg}${pluginName}${er}:${dev}${device.deviceName}${er} (${zb}${device.name}${er}): plugin not found`);
|
|
953
689
|
if (device.serverNode) {
|
|
954
|
-
// TODO: Close and remove the MatterNode managing the device
|
|
955
690
|
}
|
|
956
691
|
else if (this.matterbridge.bridgeMode === 'bridge') {
|
|
957
692
|
if (!this.aggregatorNode)
|
|
@@ -973,25 +708,11 @@ export class MatterNode extends EventEmitter {
|
|
|
973
708
|
this.log.info(`Removed bridged endpoint #${plugin.registeredDevices} ${plg}${pluginName}${nf}:${dev}${device.deviceName}${nf} (${zb}${device.name}${nf})`);
|
|
974
709
|
if (plugin.registeredDevices !== undefined)
|
|
975
710
|
plugin.registeredDevices--;
|
|
976
|
-
// Remove the device from the DeviceManager
|
|
977
711
|
await this.server.fetch({ type: 'devices_remove', src: this.server.name, dst: 'devices', params: { device: toBaseDevice(device) } });
|
|
978
712
|
await this.yieldToNode(10);
|
|
979
713
|
return device;
|
|
980
714
|
}
|
|
981
|
-
/**
|
|
982
|
-
* Removes all bridged endpoints from the specified plugin.
|
|
983
|
-
*
|
|
984
|
-
* @param {string} pluginName - The name of the plugin.
|
|
985
|
-
* @param {number} [delay] - The delay in milliseconds between removing each bridged endpoint (default: 0).
|
|
986
|
-
* @returns {Promise<void>} A promise that resolves when all bridged endpoints have been removed.
|
|
987
|
-
*
|
|
988
|
-
* @remarks
|
|
989
|
-
* This method iterates through all devices in the DeviceManager and removes each bridged endpoint associated with the specified plugin.
|
|
990
|
-
* It also applies a delay between each removal if specified.
|
|
991
|
-
* The delay is useful to allow the controllers to receive a single subscription for each device removed.
|
|
992
|
-
*/
|
|
993
715
|
async removeAllBridgedEndpoints(pluginName, delay = 0) {
|
|
994
|
-
// Check if the plugin is registered
|
|
995
716
|
const plugin = this.pluginManager.get(pluginName);
|
|
996
717
|
if (!plugin)
|
|
997
718
|
throw new Error(`Error removing all bridged endpoints for plugin ${plg}${pluginName}${er}: plugin not found`);
|
|
@@ -1006,7 +727,6 @@ export class MatterNode extends EventEmitter {
|
|
|
1006
727
|
this.log.info(`Removed bridged endpoint #${plugin.registeredDevices} ${plg}${pluginName}${nf}:${dev}${device.deviceName}${nf} (${zb}${endpoint?.name}${nf})`);
|
|
1007
728
|
if (plugin.registeredDevices !== undefined)
|
|
1008
729
|
plugin.registeredDevices--;
|
|
1009
|
-
// Remove the device from the DeviceManager
|
|
1010
730
|
await this.server.fetch({ type: 'devices_remove', src: this.server.name, dst: 'devices', params: { device: toBaseDevice(device) } });
|
|
1011
731
|
await this.yieldToNode(10);
|
|
1012
732
|
if (delay > 0)
|
|
@@ -1015,25 +735,6 @@ export class MatterNode extends EventEmitter {
|
|
|
1015
735
|
if (delay > 0)
|
|
1016
736
|
await wait(Number(process.env['MATTERBRIDGE_REMOVE_ALL_ENDPOINT_TIMEOUT_MS']) || 2000);
|
|
1017
737
|
}
|
|
1018
|
-
/**
|
|
1019
|
-
* Registers a virtual device with the Matterbridge platform.
|
|
1020
|
-
* Virtual devices are only supported in bridge mode and childbridge mode with a DynamicPlatform.
|
|
1021
|
-
*
|
|
1022
|
-
* The virtual device is created as an instance of `Endpoint` with the provided device type.
|
|
1023
|
-
* When the virtual device is turned on, the provided callback function is executed.
|
|
1024
|
-
* The onOff state of the virtual device always reverts to false when the device is turned on.
|
|
1025
|
-
*
|
|
1026
|
-
* @param {string} pluginName - The name of the plugin.
|
|
1027
|
-
* @param { string } name - The name of the virtual device.
|
|
1028
|
-
* @param { 'light' | 'outlet' | 'switch' | 'mounted_switch' } type - The type of the virtual device.
|
|
1029
|
-
* @param { () => Promise<void> } callback - The callback to call when the virtual device is turned on.
|
|
1030
|
-
*
|
|
1031
|
-
* @returns {Promise<boolean>} A promise that resolves to true if the virtual device was successfully registered, false otherwise.
|
|
1032
|
-
*
|
|
1033
|
-
* @remarks
|
|
1034
|
-
* The virtual devices don't show up in the device list of the frontend.
|
|
1035
|
-
* Type 'switch' is not supported by Alexa and 'mounted_switch' is not supported by Apple Home.
|
|
1036
|
-
*/
|
|
1037
738
|
async addVirtualEndpoint(pluginName, name, type, callback) {
|
|
1038
739
|
this.log.debug(`Creating virtual device ${plg}${pluginName}${db}:${dev}${name}${db}...`);
|
|
1039
740
|
const plugin = this.pluginManager.get(pluginName);
|
|
@@ -1058,20 +759,10 @@ export class MatterNode extends EventEmitter {
|
|
|
1058
759
|
await this.yieldToNode(10);
|
|
1059
760
|
return true;
|
|
1060
761
|
}
|
|
1061
|
-
/**
|
|
1062
|
-
* Subscribes to the attribute change event for the given device and plugin.
|
|
1063
|
-
* Specifically, it listens for changes in the 'reachable' attribute of the
|
|
1064
|
-
* BridgedDeviceBasicInformationServer cluster server of the bridged device or BasicInformationServer cluster server of server node.
|
|
1065
|
-
*
|
|
1066
|
-
* @param {Plugin} plugin - The plugin associated with the device.
|
|
1067
|
-
* @param {MatterbridgeEndpoint} device - The device to subscribe to attribute changes for.
|
|
1068
|
-
* @returns {Promise<void>} A promise that resolves when the subscription is set up.
|
|
1069
|
-
*/
|
|
1070
762
|
async subscribeAttributeChanged(plugin, device) {
|
|
1071
763
|
if (!plugin || !device || !device.plugin || !device.serialNumber || !device.uniqueId || !device.maybeNumber)
|
|
1072
764
|
return;
|
|
1073
765
|
this.log.debug(`Subscribing attributes for endpoint ${plg}${plugin.name}${db}:${dev}${device.deviceName}${db}:${or}${device.id}${db}:${or}${device.number}${db} (${zb}${device.name}${db})`);
|
|
1074
|
-
// Subscribe to the reachable$Changed event of the BasicInformationServer cluster server of the server node in childbridge mode
|
|
1075
766
|
if (this.matterbridge.bridgeMode === 'childbridge' && plugin.type === 'AccessoryPlatform' && this.serverNode) {
|
|
1076
767
|
this.serverNode.eventsOf(BasicInformationServer).reachable$Changed?.on((reachable) => {
|
|
1077
768
|
if (!device.plugin || !device.serialNumber || !device.uniqueId)
|
|
@@ -1184,12 +875,6 @@ export class MatterNode extends EventEmitter {
|
|
|
1184
875
|
}
|
|
1185
876
|
}
|
|
1186
877
|
}
|
|
1187
|
-
/**
|
|
1188
|
-
* Sanitizes the fabric information by converting bigint properties to strings because `res.json` doesn't support bigint.
|
|
1189
|
-
*
|
|
1190
|
-
* @param {ExposedFabricInformation[]} fabricInfo - The array of exposed fabric information objects.
|
|
1191
|
-
* @returns {SanitizedExposedFabricInformation[]} An array of sanitized exposed fabric information objects.
|
|
1192
|
-
*/
|
|
1193
878
|
sanitizeFabricInformations(fabricInfo) {
|
|
1194
879
|
return fabricInfo.map((info) => {
|
|
1195
880
|
return {
|
|
@@ -1203,12 +888,6 @@ export class MatterNode extends EventEmitter {
|
|
|
1203
888
|
};
|
|
1204
889
|
});
|
|
1205
890
|
}
|
|
1206
|
-
/**
|
|
1207
|
-
* Sanitizes the session information by converting bigint properties to strings because `res.json` doesn't support bigint.
|
|
1208
|
-
*
|
|
1209
|
-
* @param {SessionsBehavior.Session[]} sessions - The array of session information objects.
|
|
1210
|
-
* @returns {SanitizedSession[]} An array of sanitized session information objects.
|
|
1211
|
-
*/
|
|
1212
891
|
sanitizeSessionInformation(sessions) {
|
|
1213
892
|
return sessions
|
|
1214
893
|
.filter((session) => session.isPeerActive)
|
|
@@ -1235,21 +914,10 @@ export class MatterNode extends EventEmitter {
|
|
|
1235
914
|
};
|
|
1236
915
|
});
|
|
1237
916
|
}
|
|
1238
|
-
/**
|
|
1239
|
-
* Sets the reachability of the specified server node and trigger the corresponding event.
|
|
1240
|
-
*
|
|
1241
|
-
* @param {boolean} reachable - A boolean indicating the reachability status to set.
|
|
1242
|
-
*/
|
|
1243
917
|
async setServerReachability(reachable) {
|
|
1244
918
|
await this.serverNode?.setStateOf(BasicInformationServer, { reachable });
|
|
1245
919
|
this.serverNode?.act((agent) => this.serverNode?.eventsOf(BasicInformationServer).reachableChanged?.emit({ reachableNewValue: reachable }, agent.context));
|
|
1246
920
|
}
|
|
1247
|
-
/**
|
|
1248
|
-
* Sets the reachability of the specified aggregator node bridged devices and trigger.
|
|
1249
|
-
*
|
|
1250
|
-
* @param {Endpoint<AggregatorEndpoint>} aggregatorNode - The aggregator node to set the reachability for.
|
|
1251
|
-
* @param {boolean} reachable - A boolean indicating the reachability status to set.
|
|
1252
|
-
*/
|
|
1253
921
|
async setAggregatorReachability(aggregatorNode, reachable) {
|
|
1254
922
|
for (const child of aggregatorNode.parts) {
|
|
1255
923
|
this.log.debug(`Setting reachability of ${child?.deviceName} to ${reachable}`);
|
|
@@ -1295,35 +963,19 @@ export class MatterNode extends EventEmitter {
|
|
|
1295
963
|
case 0x1488:
|
|
1296
964
|
vendorName = '(ShortcutLabsFlic)';
|
|
1297
965
|
break;
|
|
1298
|
-
case 65521:
|
|
966
|
+
case 65521:
|
|
1299
967
|
vendorName = '(MatterTest)';
|
|
1300
968
|
break;
|
|
1301
969
|
}
|
|
1302
970
|
return vendorName;
|
|
1303
971
|
};
|
|
1304
|
-
/**
|
|
1305
|
-
* Yield to the Node.js event loop:
|
|
1306
|
-
* 1. Flushes the current microtask queue (Promise/async continuations queued so far).
|
|
1307
|
-
* 2. Yields one macrotask turn (setImmediate) and then its microtasks.
|
|
1308
|
-
* 3. Waits a bit (setTimeout) to allow other macrotasks to run.
|
|
1309
|
-
*
|
|
1310
|
-
* This does **not** guarantee that every promise in the process is settled,
|
|
1311
|
-
* but it gives all already-scheduled work a very good chance to run before continuing.
|
|
1312
|
-
*
|
|
1313
|
-
* @param {number} [timeout] - Optional timeout in milliseconds to wait after yielding. Default is 100 ms (minimum 10 ms).
|
|
1314
|
-
* @returns {Promise<void>}
|
|
1315
|
-
*/
|
|
1316
972
|
async yieldToNode(timeout = 100) {
|
|
1317
|
-
// 1. Let all currently queued microtasks run
|
|
1318
973
|
await Promise.resolve();
|
|
1319
|
-
// 2. Yield to the next event-loop turn (macrotask + its microtasks)
|
|
1320
974
|
await new Promise((resolve) => {
|
|
1321
975
|
setImmediate(resolve);
|
|
1322
976
|
});
|
|
1323
|
-
// 3. Pause a bit to allow other macrotasks to run
|
|
1324
977
|
await new Promise((resolve) => {
|
|
1325
978
|
setTimeout(resolve, Math.min(timeout, 10));
|
|
1326
979
|
});
|
|
1327
980
|
}
|
|
1328
981
|
}
|
|
1329
|
-
//# sourceMappingURL=matterNode.js.map
|