matterbridge 3.4.1 → 3.4.2-dev-20251202-c41a119
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 +20 -0
- package/dist/broadcastServer.js +0 -112
- package/dist/broadcastServerTypes.js +0 -24
- package/dist/cli.js +1 -97
- package/dist/cliEmitter.js +0 -37
- package/dist/cliHistory.js +0 -38
- package/dist/clusters/export.js +0 -2
- package/dist/deviceManager.js +1 -113
- package/dist/devices/airConditioner.js +0 -57
- package/dist/devices/batteryStorage.js +1 -48
- package/dist/devices/cooktop.js +0 -56
- package/dist/devices/dishwasher.js +0 -57
- package/dist/devices/evse.js +10 -74
- package/dist/devices/export.js +0 -5
- package/dist/devices/extractorHood.js +0 -43
- 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 +0 -102
- package/dist/devices/roboticVacuumCleaner.js +9 -100
- package/dist/devices/solarPower.js +0 -38
- package/dist/devices/speaker.js +0 -84
- package/dist/devices/temperatureControl.js +3 -24
- package/dist/devices/waterHeater.js +2 -82
- package/dist/dgram/coap.js +13 -126
- package/dist/dgram/dgram.js +2 -114
- package/dist/dgram/mb_coap.js +3 -41
- package/dist/dgram/mb_mdns.js +15 -80
- package/dist/dgram/mdns.js +137 -299
- package/dist/dgram/multicast.js +1 -62
- package/dist/dgram/unicast.js +0 -54
- package/dist/frontend.js +35 -455
- package/dist/frontendTypes.js +0 -45
- package/dist/helpers.js +0 -53
- package/dist/index.js +0 -25
- package/dist/jestutils/export.js +0 -1
- package/dist/jestutils/jestHelpers.js +13 -368
- 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/matterNode.js +8 -369
- package/dist/matterbridge.js +46 -807
- package/dist/matterbridgeAccessoryPlatform.js +0 -38
- package/dist/matterbridgeBehaviors.js +5 -68
- package/dist/matterbridgeDeviceTypes.js +14 -635
- package/dist/matterbridgeDynamicPlatform.js +0 -38
- package/dist/matterbridgeEndpoint.js +53 -1444
- package/dist/matterbridgeEndpointHelpers.js +20 -483
- package/dist/matterbridgeEndpointTypes.js +0 -25
- package/dist/matterbridgePlatform.js +1 -450
- package/dist/matterbridgeTypes.js +0 -26
- package/dist/pluginManager.js +5 -341
- package/dist/shelly.js +7 -178
- package/dist/storage/export.js +0 -1
- package/dist/update.js +1 -93
- package/dist/utils/colorUtils.js +2 -97
- package/dist/utils/commandLine.js +0 -60
- package/dist/utils/copyDirectory.js +0 -37
- 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 -42
- package/dist/utils/export.js +0 -1
- package/dist/utils/format.js +0 -49
- package/dist/utils/hex.js +0 -124
- package/dist/utils/inspector.js +1 -69
- package/dist/utils/isvalid.js +0 -101
- package/dist/utils/network.js +5 -96
- package/dist/utils/spawn.js +1 -71
- package/dist/utils/tracker.js +1 -64
- package/dist/utils/wait.js +8 -60
- package/dist/workerGlobalPrefix.js +5 -37
- package/dist/workerTypes.js +0 -24
- package/dist/workers.js +4 -68
- package/frontend/build/assets/index.js +4 -4
- package/frontend/build/assets/vendor_mui.js +1 -1
- package/frontend/package.json +1 -1
- package/npm-shrinkwrap.json +14 -10
- package/package.json +1 -2
- package/dist/broadcastServer.d.ts +0 -136
- package/dist/broadcastServer.d.ts.map +0 -1
- package/dist/broadcastServer.js.map +0 -1
- package/dist/broadcastServerTypes.d.ts +0 -841
- package/dist/broadcastServerTypes.d.ts.map +0 -1
- package/dist/broadcastServerTypes.js.map +0 -1
- package/dist/cli.d.ts +0 -30
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/cliEmitter.d.ts +0 -50
- package/dist/cliEmitter.d.ts.map +0 -1
- package/dist/cliEmitter.js.map +0 -1
- package/dist/cliHistory.d.ts +0 -48
- package/dist/cliHistory.d.ts.map +0 -1
- package/dist/cliHistory.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/deviceManager.d.ts +0 -135
- package/dist/deviceManager.d.ts.map +0 -1
- package/dist/deviceManager.js.map +0 -1
- package/dist/devices/airConditioner.d.ts +0 -98
- package/dist/devices/airConditioner.d.ts.map +0 -1
- package/dist/devices/airConditioner.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 -61
- 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 -76
- package/dist/devices/evse.d.ts.map +0 -1
- package/dist/devices/evse.js.map +0 -1
- package/dist/devices/export.d.ts +0 -17
- 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 -118
- 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/speaker.d.ts +0 -87
- package/dist/devices/speaker.d.ts.map +0 -1
- package/dist/devices/speaker.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 -141
- 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 -290
- package/dist/dgram/mdns.d.ts.map +0 -1
- package/dist/dgram/mdns.js.map +0 -1
- package/dist/dgram/multicast.d.ts +0 -67
- 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 -238
- package/dist/frontend.d.ts.map +0 -1
- package/dist/frontend.js.map +0 -1
- package/dist/frontendTypes.d.ts +0 -529
- package/dist/frontendTypes.d.ts.map +0 -1
- package/dist/frontendTypes.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 -34
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/jestutils/export.d.ts +0 -2
- package/dist/jestutils/export.d.ts.map +0 -1
- package/dist/jestutils/export.js.map +0 -1
- package/dist/jestutils/jestHelpers.d.ts +0 -340
- package/dist/jestutils/jestHelpers.d.ts.map +0 -1
- package/dist/jestutils/jestHelpers.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/matterNode.d.ts +0 -342
- package/dist/matterNode.d.ts.map +0 -1
- package/dist/matterNode.js.map +0 -1
- package/dist/matterbridge.d.ts +0 -493
- package/dist/matterbridge.d.ts.map +0 -1
- package/dist/matterbridge.js.map +0 -1
- package/dist/matterbridgeAccessoryPlatform.d.ts +0 -41
- package/dist/matterbridgeAccessoryPlatform.d.ts.map +0 -1
- package/dist/matterbridgeAccessoryPlatform.js.map +0 -1
- package/dist/matterbridgeBehaviors.d.ts +0 -2404
- package/dist/matterbridgeBehaviors.d.ts.map +0 -1
- package/dist/matterbridgeBehaviors.js.map +0 -1
- package/dist/matterbridgeDeviceTypes.d.ts +0 -698
- package/dist/matterbridgeDeviceTypes.d.ts.map +0 -1
- package/dist/matterbridgeDeviceTypes.js.map +0 -1
- package/dist/matterbridgeDynamicPlatform.d.ts +0 -41
- package/dist/matterbridgeDynamicPlatform.d.ts.map +0 -1
- package/dist/matterbridgeDynamicPlatform.js.map +0 -1
- package/dist/matterbridgeEndpoint.d.ts +0 -1507
- package/dist/matterbridgeEndpoint.d.ts.map +0 -1
- package/dist/matterbridgeEndpoint.js.map +0 -1
- package/dist/matterbridgeEndpointHelpers.d.ts +0 -787
- package/dist/matterbridgeEndpointHelpers.d.ts.map +0 -1
- package/dist/matterbridgeEndpointHelpers.js.map +0 -1
- package/dist/matterbridgeEndpointTypes.d.ts +0 -166
- package/dist/matterbridgeEndpointTypes.d.ts.map +0 -1
- package/dist/matterbridgeEndpointTypes.js.map +0 -1
- package/dist/matterbridgePlatform.d.ts +0 -537
- package/dist/matterbridgePlatform.d.ts.map +0 -1
- package/dist/matterbridgePlatform.js.map +0 -1
- package/dist/matterbridgeTypes.d.ts +0 -251
- package/dist/matterbridgeTypes.d.ts.map +0 -1
- package/dist/matterbridgeTypes.js.map +0 -1
- package/dist/pluginManager.d.ts +0 -372
- package/dist/pluginManager.d.ts.map +0 -1
- package/dist/pluginManager.js.map +0 -1
- package/dist/shelly.d.ts +0 -181
- 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 -84
- package/dist/update.d.ts.map +0 -1
- package/dist/update.js.map +0 -1
- package/dist/utils/colorUtils.d.ts +0 -101
- package/dist/utils/colorUtils.d.ts.map +0 -1
- package/dist/utils/colorUtils.js.map +0 -1
- package/dist/utils/commandLine.d.ts +0 -66
- package/dist/utils/commandLine.d.ts.map +0 -1
- package/dist/utils/commandLine.js.map +0 -1
- package/dist/utils/copyDirectory.d.ts +0 -35
- 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 -45
- package/dist/utils/error.d.ts.map +0 -1
- package/dist/utils/error.js.map +0 -1
- package/dist/utils/export.d.ts +0 -13
- package/dist/utils/export.d.ts.map +0 -1
- package/dist/utils/export.js.map +0 -1
- package/dist/utils/format.d.ts +0 -53
- package/dist/utils/format.d.ts.map +0 -1
- package/dist/utils/format.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/inspector.d.ts +0 -87
- package/dist/utils/inspector.d.ts.map +0 -1
- package/dist/utils/inspector.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 -111
- 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/tracker.d.ts +0 -108
- package/dist/utils/tracker.d.ts.map +0 -1
- package/dist/utils/tracker.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/workerGlobalPrefix.d.ts +0 -25
- package/dist/workerGlobalPrefix.d.ts.map +0 -1
- package/dist/workerGlobalPrefix.js.map +0 -1
- package/dist/workerTypes.d.ts +0 -52
- package/dist/workerTypes.d.ts.map +0 -1
- package/dist/workerTypes.js.map +0 -1
- package/dist/workers.d.ts +0 -69
- package/dist/workers.d.ts.map +0 -1
- package/dist/workers.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 { FabricAction, MdnsService } from '@matter/protocol';
|
|
@@ -49,48 +22,27 @@ import { BroadcastServer } from './broadcastServer.js';
|
|
|
49
22
|
import { toBaseDevice } from './deviceManager.js';
|
|
50
23
|
import { PluginManager } from './pluginManager.js';
|
|
51
24
|
import { addVirtualDevice } from './helpers.js';
|
|
52
|
-
/**
|
|
53
|
-
* Represents the Matter class.
|
|
54
|
-
*/
|
|
55
25
|
export class MatterNode extends EventEmitter {
|
|
56
26
|
matterbridge;
|
|
57
27
|
pluginName;
|
|
58
28
|
device;
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
/** Matter logger */
|
|
62
|
-
matterLog = new AnsiLogger({ logName: 'MatterNode', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: "debug" /* LogLevel.DEBUG */ });
|
|
63
|
-
/** Matter environment default */
|
|
29
|
+
log = new AnsiLogger({ logName: 'MatterNode', logTimestampFormat: 4, logLevel: "debug" });
|
|
30
|
+
matterLog = new AnsiLogger({ logName: 'MatterNode', logTimestampFormat: 4, logLevel: "debug" });
|
|
64
31
|
environment = Environment.default;
|
|
65
|
-
/** Matter storage id */
|
|
66
32
|
storeId;
|
|
67
|
-
/** Matter mdns service from environment default */
|
|
68
33
|
matterMdnsService;
|
|
69
|
-
/** Matter storage service from environment default */
|
|
70
34
|
matterStorageService;
|
|
71
|
-
/** Matter storage manager created with name 'Matterbridge' */
|
|
72
35
|
matterStorageManager;
|
|
73
|
-
/** Matter storage context created in the storage manager with name 'persist' */
|
|
74
36
|
matterStorageContext;
|
|
75
|
-
/** Matter mdns interface name e.g. 'eth0' or 'wlan0' or 'Wi-Fi' */
|
|
76
37
|
mdnsInterface;
|
|
77
|
-
/** Matter listeningAddressIpv4 address */
|
|
78
38
|
ipv4Address;
|
|
79
|
-
/** Matter listeningAddressIpv6 address */
|
|
80
39
|
ipv6Address;
|
|
81
|
-
/** Matter commissioning port It is incremented in childbridge mode. */
|
|
82
40
|
port;
|
|
83
|
-
/** Matter commissioning passcode. It is incremented in childbridge mode. */
|
|
84
41
|
passcode;
|
|
85
|
-
/** Matter commissioning discriminator. It is incremented in childbridge mode. */
|
|
86
42
|
discriminator;
|
|
87
|
-
/** Matter device certification */
|
|
88
43
|
certification;
|
|
89
|
-
/** Matter server node */
|
|
90
44
|
serverNode;
|
|
91
|
-
/** Matter aggregator node */
|
|
92
45
|
aggregatorNode;
|
|
93
|
-
// Default values for the aggregator node
|
|
94
46
|
aggregatorVendorId = VendorId(getIntParameter('vendorId') ?? 0xfff1);
|
|
95
47
|
aggregatorVendorName = getParameter('vendorName') ?? 'Matterbridge';
|
|
96
48
|
aggregatorProductId = getIntParameter('productId') ?? 0x8000;
|
|
@@ -98,23 +50,12 @@ export class MatterNode extends EventEmitter {
|
|
|
98
50
|
aggregatorDeviceType = DeviceTypeId(getIntParameter('deviceType') ?? bridge.code);
|
|
99
51
|
aggregatorSerialNumber = getParameter('serialNumber');
|
|
100
52
|
aggregatorUniqueId = getParameter('uniqueId');
|
|
101
|
-
/** Advertising nodes map: time advertising started keyed by storeId */
|
|
102
53
|
advertisingNodes = new Map();
|
|
103
|
-
/** Plugins */
|
|
104
54
|
pluginManager;
|
|
105
|
-
/** Dependant MatterNodes keyed by device id */
|
|
106
55
|
dependantMatterNodes = new Map();
|
|
107
|
-
/** Broadcast server */
|
|
108
56
|
server;
|
|
109
57
|
debug = hasParameter('debug') || hasParameter('verbose');
|
|
110
58
|
verbose = hasParameter('verbose');
|
|
111
|
-
/**
|
|
112
|
-
* Creates an instance of the Matter class.
|
|
113
|
-
*
|
|
114
|
-
* @param {SharedMatterbridge} matterbridge - The shared matterbridge instance.
|
|
115
|
-
* @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.
|
|
116
|
-
* @param {MatterbridgeEndpoint} [device] - The matterbridge endpoint device (optional). It is used to create a server mode device.
|
|
117
|
-
*/
|
|
118
59
|
constructor(matterbridge, pluginName, device) {
|
|
119
60
|
super();
|
|
120
61
|
this.matterbridge = matterbridge;
|
|
@@ -127,16 +68,12 @@ export class MatterNode extends EventEmitter {
|
|
|
127
68
|
this.server.on('broadcast_message', this.msgHandler.bind(this));
|
|
128
69
|
if (this.verbose)
|
|
129
70
|
this.log.debug(`BroadcastServer is ready`);
|
|
130
|
-
// Ensure the matterbridge directory exists
|
|
131
71
|
fs.mkdirSync(matterbridge.matterbridgeDirectory, { recursive: true });
|
|
132
|
-
// Setup the plugin manager with thread server closed
|
|
133
72
|
this.pluginManager = new PluginManager(this.matterbridge);
|
|
134
|
-
this.pluginManager.logLevel = this.debug ? "debug"
|
|
135
|
-
// @ts-expect-error access private property
|
|
73
|
+
this.pluginManager.logLevel = this.debug ? "debug" : "info";
|
|
136
74
|
this.pluginManager.server.close();
|
|
137
75
|
if (this.verbose)
|
|
138
76
|
this.log.debug(`PluginManager is ready`);
|
|
139
|
-
// Setup the matter environment
|
|
140
77
|
this.environment.vars.set('log.level', MatterLogLevel.DEBUG);
|
|
141
78
|
this.environment.vars.set('log.format', MatterLogFormat.ANSI);
|
|
142
79
|
this.environment.vars.set('path.root', path.join(matterbridge.matterbridgeDirectory, MATTER_STORAGE_NAME));
|
|
@@ -144,20 +81,9 @@ export class MatterNode extends EventEmitter {
|
|
|
144
81
|
this.environment.vars.set('runtime.exitcode', false);
|
|
145
82
|
if (this.verbose)
|
|
146
83
|
this.log.debug(`Matter Environment is ready`);
|
|
147
|
-
// Ensure MdnsService is registered in the default environment
|
|
148
|
-
// this.matterMdnsService = this.environment.get(MdnsService);
|
|
149
|
-
/*
|
|
150
|
-
this.matterMdnsService = new MdnsService(this.environment);
|
|
151
|
-
setImmediate(async () => {
|
|
152
|
-
await this.matterMdnsService?.construction.ready;
|
|
153
|
-
if (this.verbose) this.log.debug(`Matter MdnsService is ready`);
|
|
154
|
-
});
|
|
155
|
-
*/
|
|
156
|
-
// Setup the matterbridge logger
|
|
157
84
|
if (this.matterbridge.fileLogger) {
|
|
158
85
|
AnsiLogger.setGlobalLogfile(path.join(this.matterbridge.matterbridgeDirectory, MATTERBRIDGE_LOGGER_FILE), this.matterbridge.logLevel);
|
|
159
86
|
}
|
|
160
|
-
// Setup the matter logger
|
|
161
87
|
Logger.destinations.default.write = this.createDestinationMatterLogger();
|
|
162
88
|
const levels = ['debug', 'info', 'notice', 'warn', 'error', 'fatal'];
|
|
163
89
|
if (this.verbose)
|
|
@@ -165,11 +91,6 @@ export class MatterNode extends EventEmitter {
|
|
|
165
91
|
if (this.debug)
|
|
166
92
|
this.log.debug(`MatterNode ${this.pluginName ? 'for plugin ' + this.pluginName : 'bridge'} loaded`);
|
|
167
93
|
}
|
|
168
|
-
/**
|
|
169
|
-
* Handles incoming messages from the broadcast server.
|
|
170
|
-
*
|
|
171
|
-
* @param {WorkerMessage} msg - The incoming message.
|
|
172
|
-
*/
|
|
173
94
|
async msgHandler(msg) {
|
|
174
95
|
if (this.server.isWorkerRequest(msg) && (msg.dst === 'all' || msg.dst === 'matter')) {
|
|
175
96
|
if (this.verbose)
|
|
@@ -200,52 +121,32 @@ export class MatterNode extends EventEmitter {
|
|
|
200
121
|
}
|
|
201
122
|
}
|
|
202
123
|
}
|
|
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
124
|
async destroy(closeMdns = true) {
|
|
211
125
|
if (this.verbose)
|
|
212
126
|
this.log.debug(`Destroying MatterNode instance for ${this.storeId}...`);
|
|
213
|
-
// Close mDNS service
|
|
214
127
|
if (closeMdns) {
|
|
215
128
|
if (this.verbose)
|
|
216
129
|
this.log.debug(`Closing Matter MdnsService for ${this.storeId}...`);
|
|
217
130
|
this.matterMdnsService = this.environment.get(MdnsService);
|
|
218
|
-
// istanbul ignore next
|
|
219
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
220
131
|
if (typeof this.matterMdnsService[Symbol.asyncDispose] === 'function')
|
|
221
132
|
await this.matterMdnsService[Symbol.asyncDispose]();
|
|
222
|
-
// istanbul ignore next
|
|
223
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
224
133
|
else
|
|
225
134
|
await this.matterMdnsService.close();
|
|
226
135
|
if (this.verbose)
|
|
227
136
|
this.log.debug(`Closed Matter MdnsService for ${this.storeId}`);
|
|
228
137
|
}
|
|
229
|
-
// Close the plugin manager
|
|
230
138
|
this.pluginManager.destroy();
|
|
231
|
-
// Close the broadcast server
|
|
232
139
|
this.server.close();
|
|
233
|
-
// Yield to the Node.js event loop to allow all resources to be released
|
|
234
140
|
await this.yieldToNode();
|
|
235
141
|
if (this.verbose)
|
|
236
142
|
this.log.debug(`Destroyed MatterNode instance for ${this.storeId}`);
|
|
237
143
|
}
|
|
238
144
|
async create() {
|
|
239
145
|
this.log.info('Creating Matter node...');
|
|
240
|
-
// Start matter storage
|
|
241
146
|
await this.startMatterStorage();
|
|
242
|
-
// Load plugins from storage
|
|
243
|
-
// @ts-expect-error access private property
|
|
244
147
|
this.pluginManager.matterbridge.nodeStorage = new NodeStorageManager({ dir: path.join(this.matterbridge.matterbridgeDirectory, NODE_STORAGE_DIR), writeQueue: false, expiredInterval: undefined, logging: false });
|
|
245
|
-
// @ts-expect-error access private property
|
|
246
148
|
this.pluginManager.matterbridge.nodeContext = await this.pluginManager.matterbridge.nodeStorage.createStorage('matterbridge');
|
|
247
149
|
await this.pluginManager.loadFromStorage();
|
|
248
|
-
// Create Matter node for a server mode device
|
|
249
150
|
if (this.pluginName && this.device && this.device.deviceName) {
|
|
250
151
|
this.log.debug(`Creating MatterNode instance for server node device ${CYAN}${this.device.deviceName}${db}...`);
|
|
251
152
|
await this.createDeviceServerNode(this.pluginName, this.device);
|
|
@@ -256,7 +157,6 @@ export class MatterNode extends EventEmitter {
|
|
|
256
157
|
if (!this.pluginName) {
|
|
257
158
|
this.log.debug('Creating MatterNode instance for all plugins...');
|
|
258
159
|
await this.createMatterbridgeServerNode();
|
|
259
|
-
// Load all enabled plugins
|
|
260
160
|
this.log.debug('Loading all plugins...');
|
|
261
161
|
const loadPromises = [];
|
|
262
162
|
for (const plugin of this.pluginManager.array().filter((p) => p.enabled)) {
|
|
@@ -269,7 +169,6 @@ export class MatterNode extends EventEmitter {
|
|
|
269
169
|
}
|
|
270
170
|
else {
|
|
271
171
|
this.log.debug(`Creating MatterNode instance for plugin ${CYAN}${this.pluginName}${db}...`);
|
|
272
|
-
// Load only the specified plugin
|
|
273
172
|
this.log.debug(`Loading plugin ${CYAN}${this.pluginName}${db}...`);
|
|
274
173
|
await this.pluginManager.load(this.pluginName);
|
|
275
174
|
this.log.debug(`Loaded plugin ${CYAN}${this.pluginName}${db}`);
|
|
@@ -283,16 +182,13 @@ export class MatterNode extends EventEmitter {
|
|
|
283
182
|
if (!this.serverNode && !this.pluginName)
|
|
284
183
|
throw new Error('Matter server node not created yet. Call create() first.');
|
|
285
184
|
this.log.info('Starting MatterNode...');
|
|
286
|
-
// Start Matter node for a server mode device
|
|
287
185
|
if (this.pluginName && this.device && this.device.deviceName) {
|
|
288
|
-
// Start the server node
|
|
289
186
|
this.log.debug(`Starting MatterNode for server device ${this.pluginName}:${this.device.deviceName}...`);
|
|
290
187
|
await this.startServerNode();
|
|
291
188
|
this.log.debug(`Started MatterNode for server device ${this.pluginName}:${this.device.deviceName}`);
|
|
292
189
|
return;
|
|
293
190
|
}
|
|
294
191
|
if (!this.pluginName) {
|
|
295
|
-
// Start all loaded plugins
|
|
296
192
|
this.log.debug('Starting all plugins...');
|
|
297
193
|
const startPromises = [];
|
|
298
194
|
for (const plugin of this.pluginManager.array().filter((p) => p.enabled && p.loaded)) {
|
|
@@ -300,11 +196,9 @@ export class MatterNode extends EventEmitter {
|
|
|
300
196
|
}
|
|
301
197
|
await Promise.all(startPromises);
|
|
302
198
|
this.log.debug('Started all plugins');
|
|
303
|
-
// Start the server node
|
|
304
199
|
this.log.debug('Starting MatterNode for all plugins...');
|
|
305
200
|
await this.startServerNode();
|
|
306
201
|
this.log.debug('Started MatterNode for all plugins');
|
|
307
|
-
// Configure all loaded plugins
|
|
308
202
|
this.log.debug('Configuring all plugins...');
|
|
309
203
|
const configurePromises = [];
|
|
310
204
|
for (const plugin of this.pluginManager.array().filter((p) => p.enabled && p.started)) {
|
|
@@ -314,16 +208,12 @@ export class MatterNode extends EventEmitter {
|
|
|
314
208
|
this.log.debug('Configured all plugins');
|
|
315
209
|
}
|
|
316
210
|
else {
|
|
317
|
-
// Start the loaded plugin
|
|
318
211
|
await this.pluginManager.start(this.pluginName, 'Starting MatterNode');
|
|
319
|
-
// Start the server node
|
|
320
212
|
this.log.debug(`Starting MatterNode for plugin ${this.pluginName}...`);
|
|
321
213
|
await this.startServerNode();
|
|
322
214
|
this.log.debug(`Started MatterNode for plugin ${this.pluginName}`);
|
|
323
|
-
// Configure the plugin
|
|
324
215
|
await this.pluginManager.configure(this.pluginName);
|
|
325
216
|
}
|
|
326
|
-
// Start the dependant MatterNodes
|
|
327
217
|
this.log.debug(`Starting dependant MatterNodes...`);
|
|
328
218
|
for (const dependantMatterNode of this.dependantMatterNodes.values()) {
|
|
329
219
|
await dependantMatterNode.start();
|
|
@@ -336,15 +226,13 @@ export class MatterNode extends EventEmitter {
|
|
|
336
226
|
if (!this.serverNode)
|
|
337
227
|
throw new Error('Matter server node not created yet. Call create() first.');
|
|
338
228
|
this.log.info('Stopping MatterNode...');
|
|
339
|
-
// Stop Matter node for a server mode device
|
|
340
229
|
if (this.pluginName && this.device && this.device.deviceName) {
|
|
341
|
-
// Stop the server node
|
|
342
230
|
this.log.debug(`Stopping MatterNode for server device ${this.pluginName}:${this.device.deviceName}...`);
|
|
343
231
|
await this.stopServerNode();
|
|
344
232
|
this.serverNode = undefined;
|
|
345
233
|
this.aggregatorNode = undefined;
|
|
346
234
|
await this.stopMatterStorage();
|
|
347
|
-
await this.destroy(false);
|
|
235
|
+
await this.destroy(false);
|
|
348
236
|
this.log.debug(`Stopped MatterNode for server device ${this.pluginName}:${this.device.deviceName}`);
|
|
349
237
|
this.log.info('Stopped MatterNode');
|
|
350
238
|
await this.yieldToNode();
|
|
@@ -364,7 +252,6 @@ export class MatterNode extends EventEmitter {
|
|
|
364
252
|
await this.pluginManager.shutdown(this.pluginName, 'Stopping MatterNode');
|
|
365
253
|
this.log.debug(`Stopped plugin ${this.pluginName}`);
|
|
366
254
|
}
|
|
367
|
-
// Stop the dependant MatterNodes
|
|
368
255
|
this.log.debug(`Stopping dependant MatterNodes...`);
|
|
369
256
|
for (const dependantMatterNode of this.dependantMatterNodes.values()) {
|
|
370
257
|
await dependantMatterNode.stop();
|
|
@@ -377,46 +264,24 @@ export class MatterNode extends EventEmitter {
|
|
|
377
264
|
this.log.info('Stopped MatterNode');
|
|
378
265
|
await this.yieldToNode();
|
|
379
266
|
}
|
|
380
|
-
/**
|
|
381
|
-
* Creates a MatterLogger function to show the matter.js log messages in AnsiLogger (console and frontend).
|
|
382
|
-
* It also logs to file (matter.log) if fileLogger is true.
|
|
383
|
-
*
|
|
384
|
-
* @returns {Function} The MatterLogger function. \x1b[35m for violet \x1b[34m is blue
|
|
385
|
-
*/
|
|
386
267
|
createDestinationMatterLogger() {
|
|
387
|
-
this.matterLog.logNameColor = '\x1b[34m';
|
|
268
|
+
this.matterLog.logNameColor = '\x1b[34m';
|
|
388
269
|
if (this.matterbridge.matterFileLogger) {
|
|
389
270
|
this.matterLog.logFilePath = path.join(this.matterbridge.matterbridgeDirectory, MATTER_LOGGER_FILE);
|
|
390
271
|
}
|
|
391
272
|
return (text, message) => {
|
|
392
|
-
// 2024-08-21 08:55:19.488 DEBUG InteractionMessenger Sending DataReport chunk with 28 attributes and 0 events: 1004 bytes
|
|
393
273
|
const logger = text.slice(44, 44 + 20).trim();
|
|
394
274
|
const msg = text.slice(65);
|
|
395
275
|
this.matterLog.logName = logger;
|
|
396
276
|
this.matterLog.log(MatterLogLevel.names[message.level], msg);
|
|
397
277
|
};
|
|
398
278
|
}
|
|
399
|
-
/**
|
|
400
|
-
* Starts the matter storage with name Matterbridge and performs a backup.
|
|
401
|
-
*
|
|
402
|
-
* @returns {Promise<void>} - A promise that resolves when the storage is started.
|
|
403
|
-
*/
|
|
404
279
|
async startMatterStorage() {
|
|
405
|
-
// Setup Matter storage
|
|
406
280
|
this.log.info(`Starting matter node storage...`);
|
|
407
281
|
this.matterStorageService = this.environment.get(StorageService);
|
|
408
282
|
this.log.info(`Started matter node storage in ${CYAN}${this.matterStorageService.location}${nf}`);
|
|
409
|
-
// Backup matter storage since it is created/opened correctly
|
|
410
283
|
await this.backupMatterStorage(path.join(this.matterbridge.matterbridgeDirectory, MATTER_STORAGE_NAME), path.join(this.matterbridge.matterbridgeDirectory, MATTER_STORAGE_NAME + '.backup'));
|
|
411
284
|
}
|
|
412
|
-
/**
|
|
413
|
-
* Makes a backup copy of the specified matter storage directory.
|
|
414
|
-
*
|
|
415
|
-
* @param {string} storageName - The name of the storage directory to be backed up.
|
|
416
|
-
* @param {string} backupName - The name of the backup directory to be created.
|
|
417
|
-
* @private
|
|
418
|
-
* @returns {Promise<void>} A promise that resolves when the has been done.
|
|
419
|
-
*/
|
|
420
285
|
async backupMatterStorage(storageName, backupName) {
|
|
421
286
|
this.log.info(`Creating matter node storage backup from ${CYAN}${storageName}${nf} to ${CYAN}${backupName}${nf}...`);
|
|
422
287
|
try {
|
|
@@ -424,7 +289,6 @@ export class MatterNode extends EventEmitter {
|
|
|
424
289
|
this.log.info('Created matter node storage backup');
|
|
425
290
|
}
|
|
426
291
|
catch (error) {
|
|
427
|
-
// istanbul ignore next if
|
|
428
292
|
if (error instanceof Error && error?.code === 'ENOENT') {
|
|
429
293
|
this.log.info(`No matter node storage found to backup from ${CYAN}${storageName}${nf} to ${CYAN}${backupName}${nf}`);
|
|
430
294
|
}
|
|
@@ -433,11 +297,6 @@ export class MatterNode extends EventEmitter {
|
|
|
433
297
|
}
|
|
434
298
|
}
|
|
435
299
|
}
|
|
436
|
-
/**
|
|
437
|
-
* Stops the matter storage.
|
|
438
|
-
*
|
|
439
|
-
* @returns {Promise<void>} A promise that resolves when the storage is stopped.
|
|
440
|
-
*/
|
|
441
300
|
async stopMatterStorage() {
|
|
442
301
|
this.log.info('Closing matter node storage...');
|
|
443
302
|
await this.matterStorageManager?.close();
|
|
@@ -447,21 +306,6 @@ export class MatterNode extends EventEmitter {
|
|
|
447
306
|
this.log.info('Closed matter node storage');
|
|
448
307
|
this.emit('closed');
|
|
449
308
|
}
|
|
450
|
-
/**
|
|
451
|
-
* Creates a server node storage context.
|
|
452
|
-
*
|
|
453
|
-
* @param {string} storeId - The storeId.
|
|
454
|
-
* @param {string} deviceName - The name of the device.
|
|
455
|
-
* @param {DeviceTypeId} deviceType - The device type of the device.
|
|
456
|
-
* @param {VendorId} vendorId - The vendor ID.
|
|
457
|
-
* @param {string} vendorName - The vendor name.
|
|
458
|
-
* @param {number} productId - The product ID.
|
|
459
|
-
* @param {string} productName - The product name.
|
|
460
|
-
* @param {string} [serialNumber] - The serial number of the device (optional).
|
|
461
|
-
* @param {string} [uniqueId] - The unique ID of the device (optional).
|
|
462
|
-
* @returns {Promise<StorageContext>} The storage context for the commissioning server.
|
|
463
|
-
* @throws {Error} If the storage service is not initialized.
|
|
464
|
-
*/
|
|
465
309
|
async createServerNodeContext(storeId, deviceName, deviceType, vendorId, vendorName, productId, productName, serialNumber, uniqueId) {
|
|
466
310
|
if (!this.matterStorageService) {
|
|
467
311
|
throw new Error('No storage service initialized');
|
|
@@ -504,52 +348,33 @@ export class MatterNode extends EventEmitter {
|
|
|
504
348
|
this.log.debug(`- hardwareVersionString: ${await storageContext.get('hardwareVersionString')}`);
|
|
505
349
|
return storageContext;
|
|
506
350
|
}
|
|
507
|
-
/**
|
|
508
|
-
* Creates a server node.
|
|
509
|
-
*
|
|
510
|
-
* @param {number} [port] - The port number for the server node. Defaults to 5540.
|
|
511
|
-
* @param {number} [passcode] - The passcode for the server node. Defaults to 20242025.
|
|
512
|
-
* @param {number} [discriminator] - The discriminator for the server node. Defaults to 3850.
|
|
513
|
-
* @returns {Promise<ServerNode<ServerNode.RootEndpoint>>} A promise that resolves to the created server node.
|
|
514
|
-
* @throws {Error} If the matter storage context is not created yet.
|
|
515
|
-
*/
|
|
516
351
|
async createServerNode(port = 5540, passcode = 20252026, discriminator = 3850) {
|
|
517
352
|
if (!this.matterStorageContext) {
|
|
518
353
|
throw new Error('Matter server node context not created yet. Call createServerNodeContext() first.');
|
|
519
354
|
}
|
|
520
355
|
const storeId = await this.matterStorageContext.get('storeId');
|
|
521
356
|
this.log.notice(`Creating server node for ${storeId} on port ${port} with passcode ${passcode} and discriminator ${discriminator}...`);
|
|
522
|
-
/**
|
|
523
|
-
* Create a Matter ServerNode, which contains the Root Endpoint and all relevant data and configuration
|
|
524
|
-
*/
|
|
525
357
|
const serverNode = await ServerNode.create({
|
|
526
|
-
// Required: Give the Node a unique ID which is used to store the state of this node
|
|
527
358
|
id: storeId,
|
|
528
|
-
// Provide the environment to run this node in
|
|
529
359
|
environment: this.environment,
|
|
530
|
-
// Provide Network relevant configuration like the port
|
|
531
360
|
network: {
|
|
532
361
|
listeningAddressIpv4: this.ipv4Address,
|
|
533
362
|
listeningAddressIpv6: this.ipv6Address,
|
|
534
363
|
port,
|
|
535
364
|
},
|
|
536
|
-
// Provide the certificate for the device
|
|
537
365
|
operationalCredentials: {
|
|
538
366
|
certification: this.certification,
|
|
539
367
|
},
|
|
540
|
-
// Provide Commissioning relevant settings
|
|
541
368
|
commissioning: {
|
|
542
369
|
passcode,
|
|
543
370
|
discriminator,
|
|
544
371
|
},
|
|
545
|
-
// Provide Node announcement settings
|
|
546
372
|
productDescription: {
|
|
547
373
|
name: await this.matterStorageContext.get('deviceName'),
|
|
548
374
|
deviceType: DeviceTypeId(await this.matterStorageContext.get('deviceType')),
|
|
549
375
|
vendorId: VendorId(await this.matterStorageContext.get('vendorId')),
|
|
550
376
|
productId: await this.matterStorageContext.get('productId'),
|
|
551
377
|
},
|
|
552
|
-
// Provide defaults for the BasicInformation cluster on the Root endpoint
|
|
553
378
|
basicInformation: {
|
|
554
379
|
vendorId: VendorId(await this.matterStorageContext.get('vendorId')),
|
|
555
380
|
vendorName: await this.matterStorageContext.get('vendorName'),
|
|
@@ -566,23 +391,17 @@ export class MatterNode extends EventEmitter {
|
|
|
566
391
|
reachable: true,
|
|
567
392
|
},
|
|
568
393
|
});
|
|
569
|
-
/**
|
|
570
|
-
* This event is triggered when the device is initially commissioned successfully.
|
|
571
|
-
* This means: It is added to the first fabric.
|
|
572
|
-
*/
|
|
573
394
|
serverNode.lifecycle.commissioned.on(() => {
|
|
574
395
|
this.log.notice(`Server node for ${storeId} was initially commissioned successfully!`);
|
|
575
396
|
this.advertisingNodes.delete(storeId);
|
|
576
397
|
this.server.request({ type: 'frontend_refreshrequired', src: 'matter', dst: 'frontend', params: { changed: 'matter', matter: { ...this.getServerNodeData(serverNode) } } });
|
|
577
398
|
});
|
|
578
|
-
/** This event is triggered when all fabrics are removed from the device, usually it also does a factory reset then. */
|
|
579
399
|
serverNode.lifecycle.decommissioned.on(() => {
|
|
580
400
|
this.log.notice(`Server node for ${storeId} was fully decommissioned successfully!`);
|
|
581
401
|
this.advertisingNodes.delete(storeId);
|
|
582
402
|
this.server.request({ type: 'frontend_refreshrequired', src: 'matter', dst: 'frontend', params: { changed: 'matter', matter: { ...this.getServerNodeData(serverNode) } } });
|
|
583
403
|
this.server.request({ type: 'frontend_snackbarmessage', src: 'matter', dst: 'frontend', params: { message: `${storeId} is offline`, timeout: 5, severity: 'warning' } });
|
|
584
404
|
});
|
|
585
|
-
/** This event is triggered when the device went online. This means that it is discoverable in the network. */
|
|
586
405
|
serverNode.lifecycle.online.on(async () => {
|
|
587
406
|
this.log.notice(`Server node for ${storeId} is online`);
|
|
588
407
|
if (!serverNode.lifecycle.isCommissioned) {
|
|
@@ -600,7 +419,6 @@ export class MatterNode extends EventEmitter {
|
|
|
600
419
|
this.server.request({ type: 'frontend_snackbarmessage', src: 'matter', dst: 'frontend', params: { message: `${storeId} is online`, timeout: 5, severity: 'success' } });
|
|
601
420
|
this.emit('online', storeId);
|
|
602
421
|
});
|
|
603
|
-
/** This event is triggered when the device went offline. it is not longer discoverable or connectable in the network. */
|
|
604
422
|
serverNode.lifecycle.offline.on(() => {
|
|
605
423
|
this.log.notice(`Server node for ${storeId} is offline`);
|
|
606
424
|
this.advertisingNodes.delete(storeId);
|
|
@@ -608,15 +426,11 @@ export class MatterNode extends EventEmitter {
|
|
|
608
426
|
this.server.request({ type: 'frontend_snackbarmessage', src: 'matter', dst: 'frontend', params: { message: `${storeId} is offline`, timeout: 5, severity: 'warning' } });
|
|
609
427
|
this.emit('offline', storeId);
|
|
610
428
|
});
|
|
611
|
-
/**
|
|
612
|
-
* This event is triggered when a fabric is added, removed or updated on the device. Use this if more granular
|
|
613
|
-
* information is needed.
|
|
614
|
-
*/
|
|
615
429
|
serverNode.events.commissioning.fabricsChanged.on((fabricIndex, fabricAction) => {
|
|
616
430
|
let action = '';
|
|
617
431
|
switch (fabricAction) {
|
|
618
432
|
case FabricAction.Added:
|
|
619
|
-
this.advertisingNodes.delete(storeId);
|
|
433
|
+
this.advertisingNodes.delete(storeId);
|
|
620
434
|
action = 'added';
|
|
621
435
|
break;
|
|
622
436
|
case FabricAction.Removed:
|
|
@@ -629,22 +443,14 @@ export class MatterNode extends EventEmitter {
|
|
|
629
443
|
this.log.notice(`Commissioned fabric index ${fabricIndex} ${action} on server node for ${storeId}: ${debugStringify(serverNode.state.commissioning.fabrics[fabricIndex])}`);
|
|
630
444
|
this.server.request({ type: 'frontend_refreshrequired', src: 'matter', dst: 'frontend', params: { changed: 'matter', matter: { ...this.getServerNodeData(serverNode) } } });
|
|
631
445
|
});
|
|
632
|
-
/**
|
|
633
|
-
* This event is triggered when an operative new session was opened by a Controller.
|
|
634
|
-
* It is not triggered for the initial commissioning process, just afterwards for real connections.
|
|
635
|
-
*/
|
|
636
446
|
serverNode.events.sessions.opened.on((session) => {
|
|
637
447
|
this.log.notice(`Session opened on server node for ${storeId}: ${debugStringify(session)}`);
|
|
638
448
|
this.server.request({ type: 'frontend_refreshrequired', src: 'matter', dst: 'frontend', params: { changed: 'matter', matter: { ...this.getServerNodeData(serverNode) } } });
|
|
639
449
|
});
|
|
640
|
-
/**
|
|
641
|
-
* This event is triggered when an operative session is closed by a Controller or because the Device goes offline.
|
|
642
|
-
*/
|
|
643
450
|
serverNode.events.sessions.closed.on((session) => {
|
|
644
451
|
this.log.notice(`Session closed on server node for ${storeId}: ${debugStringify(session)}`);
|
|
645
452
|
this.server.request({ type: 'frontend_refreshrequired', src: 'matter', dst: 'frontend', params: { changed: 'matter', matter: { ...this.getServerNodeData(serverNode) } } });
|
|
646
453
|
});
|
|
647
|
-
/** This event is triggered when a subscription gets added or removed on an operative session. */
|
|
648
454
|
serverNode.events.sessions.subscriptionsChanged.on((session) => {
|
|
649
455
|
this.log.notice(`Session subscriptions changed on server node for ${storeId}: ${debugStringify(session)}`);
|
|
650
456
|
this.server.request({ type: 'frontend_refreshrequired', src: 'matter', dst: 'frontend', params: { changed: 'matter', matter: { ...this.getServerNodeData(serverNode) } } });
|
|
@@ -653,12 +459,6 @@ export class MatterNode extends EventEmitter {
|
|
|
653
459
|
this.log.info(`Created server node for ${this.storeId}`);
|
|
654
460
|
return serverNode;
|
|
655
461
|
}
|
|
656
|
-
/**
|
|
657
|
-
* Gets the matter serializable data of the specified server node.
|
|
658
|
-
*
|
|
659
|
-
* @param {ServerNode} [serverNode] - The server node to start.
|
|
660
|
-
* @returns {ApiMatter} The serializable data of the server node.
|
|
661
|
-
*/
|
|
662
462
|
getServerNodeData(serverNode) {
|
|
663
463
|
const advertiseTime = this.advertisingNodes.get(serverNode.id) || 0;
|
|
664
464
|
return {
|
|
@@ -675,13 +475,6 @@ export class MatterNode extends EventEmitter {
|
|
|
675
475
|
serialNumber: serverNode.state.basicInformation.serialNumber,
|
|
676
476
|
};
|
|
677
477
|
}
|
|
678
|
-
/**
|
|
679
|
-
* Starts the specified server node.
|
|
680
|
-
*
|
|
681
|
-
* @param {number} [timeout] - The timeout in milliseconds for starting the server node. Defaults to 30 seconds.
|
|
682
|
-
* @returns {Promise<void>} A promise that resolves when the server node has started.
|
|
683
|
-
* @throws {Error} If the server node is not created yet.
|
|
684
|
-
*/
|
|
685
478
|
async startServerNode(timeout = 30000) {
|
|
686
479
|
if (!this.serverNode) {
|
|
687
480
|
throw new Error('Matter server node not created yet. Call create() first.');
|
|
@@ -692,17 +485,9 @@ export class MatterNode extends EventEmitter {
|
|
|
692
485
|
this.log.notice(`Started ${this.serverNode.id} server node`);
|
|
693
486
|
}
|
|
694
487
|
catch (error) {
|
|
695
|
-
// istanbul ignore next
|
|
696
488
|
this.log.error(`Failed to start ${this.serverNode.id} server node: ${error instanceof Error ? error.message : error}`);
|
|
697
489
|
}
|
|
698
490
|
}
|
|
699
|
-
/**
|
|
700
|
-
* Stops the specified server node.
|
|
701
|
-
*
|
|
702
|
-
* @param {number} [timeout] - The timeout in milliseconds for stopping the server node. Defaults to 30 seconds.
|
|
703
|
-
* @returns {Promise<void>} A promise that resolves when the server node has stopped.
|
|
704
|
-
* @throws {Error} If the server node is not created yet.
|
|
705
|
-
*/
|
|
706
491
|
async stopServerNode(timeout = 30000) {
|
|
707
492
|
if (!this.serverNode) {
|
|
708
493
|
throw new Error('Matter server node not created yet. Call create() first.');
|
|
@@ -713,16 +498,9 @@ export class MatterNode extends EventEmitter {
|
|
|
713
498
|
this.log.info(`Closed ${this.serverNode.id} server node`);
|
|
714
499
|
}
|
|
715
500
|
catch (error) {
|
|
716
|
-
// istanbul ignore next
|
|
717
501
|
this.log.error(`Failed to close ${this.serverNode.id} server node: ${error instanceof Error ? error.message : error}`);
|
|
718
502
|
}
|
|
719
503
|
}
|
|
720
|
-
/**
|
|
721
|
-
* Creates an aggregator node with the specified storage context.
|
|
722
|
-
*
|
|
723
|
-
* @returns {Promise<Endpoint<AggregatorEndpoint>>} A promise that resolves to the created aggregator node.
|
|
724
|
-
* @throws {Error} If the matter storage context is not created yet.
|
|
725
|
-
*/
|
|
726
504
|
async createAggregatorNode() {
|
|
727
505
|
if (!this.matterStorageContext) {
|
|
728
506
|
throw new Error('Matter server node context not created yet. Call createServerNodeContext() first.');
|
|
@@ -732,16 +510,9 @@ export class MatterNode extends EventEmitter {
|
|
|
732
510
|
this.log.info(`Created ${await this.matterStorageContext.get('storeId')} aggregator`);
|
|
733
511
|
return aggregatorNode;
|
|
734
512
|
}
|
|
735
|
-
/**
|
|
736
|
-
* Creates the matterbridge server node.
|
|
737
|
-
*
|
|
738
|
-
* @returns {Promise<ServerNode<ServerNode.RootEndpoint>>} A promise that resolves to the created matterbridge server node.
|
|
739
|
-
*/
|
|
740
513
|
async createMatterbridgeServerNode() {
|
|
741
514
|
this.log.debug(`Creating ${plg}Matterbridge${db} server node...`);
|
|
742
|
-
this.matterStorageContext = await this.createServerNodeContext('Matterbridge',
|
|
743
|
-
'Matterbridge', // deviceName
|
|
744
|
-
this.aggregatorDeviceType, this.aggregatorVendorId, this.aggregatorVendorName, this.aggregatorProductId, this.aggregatorProductName, this.aggregatorSerialNumber, this.aggregatorUniqueId);
|
|
515
|
+
this.matterStorageContext = await this.createServerNodeContext('Matterbridge', 'Matterbridge', this.aggregatorDeviceType, this.aggregatorVendorId, this.aggregatorVendorName, this.aggregatorProductId, this.aggregatorProductName, this.aggregatorSerialNumber, this.aggregatorUniqueId);
|
|
745
516
|
this.serverNode = await this.createServerNode(this.port ? this.port++ : undefined, this.passcode ? this.passcode++ : undefined, this.discriminator ? this.discriminator++ : undefined);
|
|
746
517
|
this.aggregatorNode = await this.createAggregatorNode();
|
|
747
518
|
this.log.debug(`Adding ${plg}Matterbridge${db} aggregator node...`);
|
|
@@ -752,13 +523,6 @@ export class MatterNode extends EventEmitter {
|
|
|
752
523
|
this.log.debug(`Created ${plg}Matterbridge${db} server node`);
|
|
753
524
|
return this.serverNode;
|
|
754
525
|
}
|
|
755
|
-
/**
|
|
756
|
-
* Creates and configures the server node for an accessory plugin for a given device.
|
|
757
|
-
*
|
|
758
|
-
* @param {Plugin | PluginName} plugin - The plugin to configure.
|
|
759
|
-
* @param {MatterbridgeEndpoint} device - The device to associate with the plugin.
|
|
760
|
-
* @returns {Promise<ServerNode<ServerNode.RootEndpoint> | undefined>} A promise that resolves to the server node for the accessory plugin.
|
|
761
|
-
*/
|
|
762
526
|
async createAccessoryPlugin(plugin, device) {
|
|
763
527
|
if (typeof plugin === 'string') {
|
|
764
528
|
const _plugin = this.pluginManager.get(plugin);
|
|
@@ -780,12 +544,6 @@ export class MatterNode extends EventEmitter {
|
|
|
780
544
|
}
|
|
781
545
|
return this.serverNode;
|
|
782
546
|
}
|
|
783
|
-
/**
|
|
784
|
-
* Creates and configures the server node and the aggregator node for a dynamic plugin.
|
|
785
|
-
*
|
|
786
|
-
* @param {Plugin | PluginName} plugin - The plugin to configure.
|
|
787
|
-
* @returns {Promise<ServerNode<ServerNode.RootEndpoint> | undefined>} A promise that resolves to the server node for the dynamic plugin.
|
|
788
|
-
*/
|
|
789
547
|
async createDynamicPlugin(plugin) {
|
|
790
548
|
if (typeof plugin === 'string') {
|
|
791
549
|
const _plugin = this.pluginManager.get(plugin);
|
|
@@ -809,13 +567,6 @@ export class MatterNode extends EventEmitter {
|
|
|
809
567
|
}
|
|
810
568
|
return this.serverNode;
|
|
811
569
|
}
|
|
812
|
-
/**
|
|
813
|
-
* Creates and configures the server node for a single not bridged device.
|
|
814
|
-
*
|
|
815
|
-
* @param {Plugin | PluginName} plugin - The plugin to configure.
|
|
816
|
-
* @param {MatterbridgeEndpoint} device - The device to associate with the plugin.
|
|
817
|
-
* @returns {Promise<ServerNode<ServerNode.RootEndpoint> | undefined>} A promise that resolves to the server node for the device with mode server.
|
|
818
|
-
*/
|
|
819
570
|
async createDeviceServerNode(plugin, device) {
|
|
820
571
|
if (typeof plugin === 'string') {
|
|
821
572
|
const _plugin = this.pluginManager.get(plugin);
|
|
@@ -836,22 +587,13 @@ export class MatterNode extends EventEmitter {
|
|
|
836
587
|
}
|
|
837
588
|
return this.serverNode;
|
|
838
589
|
}
|
|
839
|
-
/**
|
|
840
|
-
* Adds a MatterbridgeEndpoint to the specified plugin.
|
|
841
|
-
*
|
|
842
|
-
* @param {string} pluginName - The name of the plugin.
|
|
843
|
-
* @param {MatterbridgeEndpoint} device - The device to add as a bridged endpoint.
|
|
844
|
-
* @returns {Promise<MatterbridgeEndpoint | undefined>} A promise that resolves to the added bridged endpoint, or undefined if there was an error.
|
|
845
|
-
*/
|
|
846
590
|
async addBridgedEndpoint(pluginName, device) {
|
|
847
|
-
// Check if the plugin is registered
|
|
848
591
|
const plugin = this.pluginManager.get(pluginName);
|
|
849
592
|
if (!plugin)
|
|
850
593
|
throw new Error(`Error adding bridged endpoint ${plg}${pluginName}${er}:${dev}${device.deviceName}${er} (${zb}${device.name}${er}): plugin not found`);
|
|
851
594
|
if (device.mode === 'server') {
|
|
852
595
|
try {
|
|
853
596
|
this.log.debug(`Creating MatterNode for device ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} (${zb}${device.name}${db})...`);
|
|
854
|
-
// Create the MatterNode to manage the device
|
|
855
597
|
const matterNode = new MatterNode(this.matterbridge, pluginName, device);
|
|
856
598
|
this.dependantMatterNodes.set(device.id, matterNode);
|
|
857
599
|
await matterNode.create();
|
|
@@ -864,7 +606,6 @@ export class MatterNode extends EventEmitter {
|
|
|
864
606
|
}
|
|
865
607
|
else if (this.matterbridge.bridgeMode === 'bridge') {
|
|
866
608
|
if (device.mode === 'matter') {
|
|
867
|
-
// Register and add the device to the Matter server node
|
|
868
609
|
this.log.debug(`Adding matter endpoint ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} (${zb}${device.name}${db})...`);
|
|
869
610
|
if (!this.serverNode)
|
|
870
611
|
throw new Error(`Server node not found for matter endpoint ${plg}${pluginName}${er}:${dev}${device.deviceName}${er} (${zb}${device.name}${er})`);
|
|
@@ -877,7 +618,6 @@ export class MatterNode extends EventEmitter {
|
|
|
877
618
|
}
|
|
878
619
|
}
|
|
879
620
|
else {
|
|
880
|
-
// Register and add the device to the Matter aggregator node
|
|
881
621
|
this.log.debug(`Adding bridged endpoint ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} (${zb}${device.name}${db})...`);
|
|
882
622
|
if (!this.aggregatorNode)
|
|
883
623
|
throw new Error(`Aggregator node not found for endpoint ${plg}${pluginName}${er}:${dev}${device.deviceName}${er} (${zb}${device.name}${er})`);
|
|
@@ -891,7 +631,6 @@ export class MatterNode extends EventEmitter {
|
|
|
891
631
|
}
|
|
892
632
|
}
|
|
893
633
|
else if (this.matterbridge.bridgeMode === 'childbridge') {
|
|
894
|
-
// Register and add the device to the plugin server node
|
|
895
634
|
if (plugin.type === 'AccessoryPlatform') {
|
|
896
635
|
try {
|
|
897
636
|
this.log.debug(`Adding accessory endpoint ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} (${zb}${device.name}${db})...`);
|
|
@@ -907,12 +646,10 @@ export class MatterNode extends EventEmitter {
|
|
|
907
646
|
return;
|
|
908
647
|
}
|
|
909
648
|
}
|
|
910
|
-
// Register and add the device to the plugin aggregator node
|
|
911
649
|
if (plugin.type === 'DynamicPlatform') {
|
|
912
650
|
try {
|
|
913
651
|
this.log.debug(`Adding bridged endpoint ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} (${zb}${device.name}${db})...`);
|
|
914
652
|
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
653
|
await this.createDynamicPlugin(plugin);
|
|
917
654
|
}
|
|
918
655
|
if (device.mode === 'matter')
|
|
@@ -928,30 +665,18 @@ export class MatterNode extends EventEmitter {
|
|
|
928
665
|
}
|
|
929
666
|
if (plugin.registeredDevices !== undefined)
|
|
930
667
|
plugin.registeredDevices++;
|
|
931
|
-
// Add the device to the DeviceManager
|
|
932
668
|
await this.server.fetch({ type: 'devices_set', src: this.server.name, dst: 'devices', params: { device: toBaseDevice(device) } });
|
|
933
|
-
// Add the device to the DeviceManager
|
|
934
669
|
await device.construction.ready;
|
|
935
|
-
// Subscribe to the attributes changed event
|
|
936
670
|
await this.subscribeAttributeChanged(plugin, device);
|
|
937
671
|
this.log.info(`Added endpoint #${plugin.registeredDevices} ${plg}${pluginName}${nf}:${dev}${device.deviceName}${nf} (${zb}${device.name}${nf})`);
|
|
938
672
|
await this.yieldToNode(10);
|
|
939
673
|
return device;
|
|
940
674
|
}
|
|
941
|
-
/**
|
|
942
|
-
* Removes a MatterbridgeEndpoint from the specified plugin.
|
|
943
|
-
*
|
|
944
|
-
* @param {string} pluginName - The name of the plugin.
|
|
945
|
-
* @param {MatterbridgeEndpoint} device - The device to remove as a bridged endpoint.
|
|
946
|
-
* @returns {Promise<MatterbridgeEndpoint | undefined>} A promise that resolves to the removed bridged endpoint, or undefined if there was an error.
|
|
947
|
-
*/
|
|
948
675
|
async removeBridgedEndpoint(pluginName, device) {
|
|
949
676
|
this.log.debug(`Removing bridged endpoint ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} (${zb}${device.name}${db})...`);
|
|
950
|
-
// Check if the plugin is registered
|
|
951
677
|
const plugin = this.pluginManager.get(pluginName);
|
|
952
678
|
if (!plugin)
|
|
953
679
|
throw new Error(`Error removing bridged endpoint ${plg}${pluginName}${er}:${dev}${device.deviceName}${er} (${zb}${device.name}${er}): plugin not found`);
|
|
954
|
-
// Remove the device from the Matter aggregator node
|
|
955
680
|
if (this.matterbridge.bridgeMode === 'bridge') {
|
|
956
681
|
if (!this.aggregatorNode)
|
|
957
682
|
throw new Error(`Error removing bridged endpoint ${plg}${pluginName}${er}:${dev}${device.deviceName}${er} (${zb}${device.name}${er}): aggregator node not found`);
|
|
@@ -972,25 +697,11 @@ export class MatterNode extends EventEmitter {
|
|
|
972
697
|
this.log.info(`Removed bridged endpoint #${plugin.registeredDevices} ${plg}${pluginName}${nf}:${dev}${device.deviceName}${nf} (${zb}${device.name}${nf})`);
|
|
973
698
|
if (plugin.registeredDevices !== undefined)
|
|
974
699
|
plugin.registeredDevices--;
|
|
975
|
-
// Remove the device from the DeviceManager
|
|
976
700
|
await this.server.fetch({ type: 'devices_remove', src: this.server.name, dst: 'devices', params: { device: toBaseDevice(device) } });
|
|
977
701
|
await this.yieldToNode(10);
|
|
978
702
|
return device;
|
|
979
703
|
}
|
|
980
|
-
/**
|
|
981
|
-
* Removes all bridged endpoints from the specified plugin.
|
|
982
|
-
*
|
|
983
|
-
* @param {string} pluginName - The name of the plugin.
|
|
984
|
-
* @param {number} [delay] - The delay in milliseconds between removing each bridged endpoint (default: 0).
|
|
985
|
-
* @returns {Promise<void>} A promise that resolves when all bridged endpoints have been removed.
|
|
986
|
-
*
|
|
987
|
-
* @remarks
|
|
988
|
-
* This method iterates through all devices in the DeviceManager and removes each bridged endpoint associated with the specified plugin.
|
|
989
|
-
* It also applies a delay between each removal if specified.
|
|
990
|
-
* The delay is useful to allow the controllers to receive a single subscription for each device removed.
|
|
991
|
-
*/
|
|
992
704
|
async removeAllBridgedEndpoints(pluginName, delay = 0) {
|
|
993
|
-
// Check if the plugin is registered
|
|
994
705
|
const plugin = this.pluginManager.get(pluginName);
|
|
995
706
|
if (!plugin)
|
|
996
707
|
throw new Error(`Error removing all bridged endpoints for plugin ${plg}${pluginName}${er}: plugin not found`);
|
|
@@ -1005,7 +716,6 @@ export class MatterNode extends EventEmitter {
|
|
|
1005
716
|
this.log.info(`Removed bridged endpoint #${plugin.registeredDevices} ${plg}${pluginName}${nf}:${dev}${device.deviceName}${nf} (${zb}${endpoint?.name}${nf})`);
|
|
1006
717
|
if (plugin.registeredDevices !== undefined)
|
|
1007
718
|
plugin.registeredDevices--;
|
|
1008
|
-
// Remove the device from the DeviceManager
|
|
1009
719
|
await this.server.fetch({ type: 'devices_remove', src: this.server.name, dst: 'devices', params: { device: toBaseDevice(device) } });
|
|
1010
720
|
await this.yieldToNode(10);
|
|
1011
721
|
if (delay > 0)
|
|
@@ -1014,25 +724,6 @@ export class MatterNode extends EventEmitter {
|
|
|
1014
724
|
if (delay > 0)
|
|
1015
725
|
await wait(Number(process.env['MATTERBRIDGE_REMOVE_ALL_ENDPOINT_TIMEOUT_MS']) || 2000);
|
|
1016
726
|
}
|
|
1017
|
-
/**
|
|
1018
|
-
* Registers a virtual device with the Matterbridge platform.
|
|
1019
|
-
* Virtual devices are only supported in bridge mode and childbridge mode with a DynamicPlatform.
|
|
1020
|
-
*
|
|
1021
|
-
* The virtual device is created as an instance of `Endpoint` with the provided device type.
|
|
1022
|
-
* When the virtual device is turned on, the provided callback function is executed.
|
|
1023
|
-
* The onOff state of the virtual device always reverts to false when the device is turned on.
|
|
1024
|
-
*
|
|
1025
|
-
* @param {string} pluginName - The name of the plugin.
|
|
1026
|
-
* @param { string } name - The name of the virtual device.
|
|
1027
|
-
* @param { 'light' | 'outlet' | 'switch' | 'mounted_switch' } type - The type of the virtual device.
|
|
1028
|
-
* @param { () => Promise<void> } callback - The callback to call when the virtual device is turned on.
|
|
1029
|
-
*
|
|
1030
|
-
* @returns {Promise<boolean>} A promise that resolves to true if the virtual device was successfully registered, false otherwise.
|
|
1031
|
-
*
|
|
1032
|
-
* @remarks
|
|
1033
|
-
* The virtual devices don't show up in the device list of the frontend.
|
|
1034
|
-
* Type 'switch' is not supported by Alexa and 'mounted_switch' is not supported by Apple Home.
|
|
1035
|
-
*/
|
|
1036
727
|
async addVirtualEndpoint(pluginName, name, type, callback) {
|
|
1037
728
|
this.log.debug(`Creating virtual device ${plg}${pluginName}${db}:${dev}${name}${db}...`);
|
|
1038
729
|
const plugin = this.pluginManager.get(pluginName);
|
|
@@ -1057,20 +748,10 @@ export class MatterNode extends EventEmitter {
|
|
|
1057
748
|
await this.yieldToNode(10);
|
|
1058
749
|
return true;
|
|
1059
750
|
}
|
|
1060
|
-
/**
|
|
1061
|
-
* Subscribes to the attribute change event for the given device and plugin.
|
|
1062
|
-
* Specifically, it listens for changes in the 'reachable' attribute of the
|
|
1063
|
-
* BridgedDeviceBasicInformationServer cluster server of the bridged device or BasicInformationServer cluster server of server node.
|
|
1064
|
-
*
|
|
1065
|
-
* @param {Plugin} plugin - The plugin associated with the device.
|
|
1066
|
-
* @param {MatterbridgeEndpoint} device - The device to subscribe to attribute changes for.
|
|
1067
|
-
* @returns {Promise<void>} A promise that resolves when the subscription is set up.
|
|
1068
|
-
*/
|
|
1069
751
|
async subscribeAttributeChanged(plugin, device) {
|
|
1070
752
|
if (!plugin || !device || !device.plugin || !device.serialNumber || !device.uniqueId || !device.maybeNumber)
|
|
1071
753
|
return;
|
|
1072
754
|
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})`);
|
|
1073
|
-
// Subscribe to the reachable$Changed event of the BasicInformationServer cluster server of the server node in childbridge mode
|
|
1074
755
|
if (this.matterbridge.bridgeMode === 'childbridge' && plugin.type === 'AccessoryPlatform' && this.serverNode) {
|
|
1075
756
|
this.serverNode.eventsOf(BasicInformationServer).reachable$Changed?.on((reachable) => {
|
|
1076
757
|
this.log.debug(`Accessory endpoint ${plg}${plugin.name}${nf}:${dev}${device.deviceName}${nf}:${or}${device.id}${nf}:${or}${device.number}${nf} is ${reachable ? 'reachable' : 'unreachable'}`);
|
|
@@ -1078,7 +759,6 @@ export class MatterNode extends EventEmitter {
|
|
|
1078
759
|
type: 'frontend_attributechanged',
|
|
1079
760
|
src: 'matter',
|
|
1080
761
|
dst: 'frontend',
|
|
1081
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
1082
762
|
params: { plugin: device.plugin, serialNumber: device.serialNumber, uniqueId: device.uniqueId, number: device.number, id: device.id, cluster: 'BasicInformation', attribute: 'reachable', value: reachable },
|
|
1083
763
|
});
|
|
1084
764
|
});
|
|
@@ -1131,7 +811,6 @@ export class MatterNode extends EventEmitter {
|
|
|
1131
811
|
type: 'frontend_attributechanged',
|
|
1132
812
|
src: 'matter',
|
|
1133
813
|
dst: 'frontend',
|
|
1134
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
1135
814
|
params: { plugin: device.plugin, serialNumber: device.serialNumber, uniqueId: device.uniqueId, number: device.number, id: device.id, cluster: sub.cluster, attribute: sub.attribute, value: value },
|
|
1136
815
|
});
|
|
1137
816
|
});
|
|
@@ -1145,7 +824,6 @@ export class MatterNode extends EventEmitter {
|
|
|
1145
824
|
type: 'frontend_attributechanged',
|
|
1146
825
|
src: 'matter',
|
|
1147
826
|
dst: 'frontend',
|
|
1148
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
1149
827
|
params: { plugin: device.plugin, serialNumber: device.serialNumber, uniqueId: device.uniqueId, number: child.number, id: child.id, cluster: sub.cluster, attribute: sub.attribute, value: value },
|
|
1150
828
|
});
|
|
1151
829
|
});
|
|
@@ -1153,12 +831,6 @@ export class MatterNode extends EventEmitter {
|
|
|
1153
831
|
}
|
|
1154
832
|
}
|
|
1155
833
|
}
|
|
1156
|
-
/**
|
|
1157
|
-
* Sanitizes the fabric information by converting bigint properties to strings because `res.json` doesn't support bigint.
|
|
1158
|
-
*
|
|
1159
|
-
* @param {ExposedFabricInformation[]} fabricInfo - The array of exposed fabric information objects.
|
|
1160
|
-
* @returns {SanitizedExposedFabricInformation[]} An array of sanitized exposed fabric information objects.
|
|
1161
|
-
*/
|
|
1162
834
|
sanitizeFabricInformations(fabricInfo) {
|
|
1163
835
|
return fabricInfo.map((info) => {
|
|
1164
836
|
return {
|
|
@@ -1172,12 +844,6 @@ export class MatterNode extends EventEmitter {
|
|
|
1172
844
|
};
|
|
1173
845
|
});
|
|
1174
846
|
}
|
|
1175
|
-
/**
|
|
1176
|
-
* Sanitizes the session information by converting bigint properties to strings because `res.json` doesn't support bigint.
|
|
1177
|
-
*
|
|
1178
|
-
* @param {SessionsBehavior.Session[]} sessions - The array of session information objects.
|
|
1179
|
-
* @returns {SanitizedSession[]} An array of sanitized session information objects.
|
|
1180
|
-
*/
|
|
1181
847
|
sanitizeSessionInformation(sessions) {
|
|
1182
848
|
return sessions
|
|
1183
849
|
.filter((session) => session.isPeerActive)
|
|
@@ -1204,21 +870,10 @@ export class MatterNode extends EventEmitter {
|
|
|
1204
870
|
};
|
|
1205
871
|
});
|
|
1206
872
|
}
|
|
1207
|
-
/**
|
|
1208
|
-
* Sets the reachability of the specified server node and trigger the corresponding event.
|
|
1209
|
-
*
|
|
1210
|
-
* @param {boolean} reachable - A boolean indicating the reachability status to set.
|
|
1211
|
-
*/
|
|
1212
873
|
async setServerReachability(reachable) {
|
|
1213
874
|
await this.serverNode?.setStateOf(BasicInformationServer, { reachable });
|
|
1214
875
|
this.serverNode?.act((agent) => this.serverNode?.eventsOf(BasicInformationServer).reachableChanged?.emit({ reachableNewValue: reachable }, agent.context));
|
|
1215
876
|
}
|
|
1216
|
-
/**
|
|
1217
|
-
* Sets the reachability of the specified aggregator node bridged devices and trigger.
|
|
1218
|
-
*
|
|
1219
|
-
* @param {Endpoint<AggregatorEndpoint>} aggregatorNode - The aggregator node to set the reachability for.
|
|
1220
|
-
* @param {boolean} reachable - A boolean indicating the reachability status to set.
|
|
1221
|
-
*/
|
|
1222
877
|
async setAggregatorReachability(aggregatorNode, reachable) {
|
|
1223
878
|
for (const child of aggregatorNode.parts) {
|
|
1224
879
|
this.log.debug(`Setting reachability of ${child?.deviceName} to ${reachable}`);
|
|
@@ -1264,35 +919,19 @@ export class MatterNode extends EventEmitter {
|
|
|
1264
919
|
case 0x1488:
|
|
1265
920
|
vendorName = '(ShortcutLabsFlic)';
|
|
1266
921
|
break;
|
|
1267
|
-
case 65521:
|
|
922
|
+
case 65521:
|
|
1268
923
|
vendorName = '(MatterTest)';
|
|
1269
924
|
break;
|
|
1270
925
|
}
|
|
1271
926
|
return vendorName;
|
|
1272
927
|
};
|
|
1273
|
-
/**
|
|
1274
|
-
* Yield to the Node.js event loop:
|
|
1275
|
-
* 1. Flushes the current microtask queue (Promise/async continuations queued so far).
|
|
1276
|
-
* 2. Yields one macrotask turn (setImmediate) and then its microtasks.
|
|
1277
|
-
* 3. Waits a bit (setTimeout) to allow other macrotasks to run.
|
|
1278
|
-
*
|
|
1279
|
-
* This does **not** guarantee that every promise in the process is settled,
|
|
1280
|
-
* but it gives all already-scheduled work a very good chance to run before continuing.
|
|
1281
|
-
*
|
|
1282
|
-
* @param {number} [timeout] - Optional timeout in milliseconds to wait after yielding. Default is 100 ms (minimum 10 ms).
|
|
1283
|
-
* @returns {Promise<void>}
|
|
1284
|
-
*/
|
|
1285
928
|
async yieldToNode(timeout = 100) {
|
|
1286
|
-
// 1. Let all currently queued microtasks run
|
|
1287
929
|
await Promise.resolve();
|
|
1288
|
-
// 2. Yield to the next event-loop turn (macrotask + its microtasks)
|
|
1289
930
|
await new Promise((resolve) => {
|
|
1290
931
|
setImmediate(resolve);
|
|
1291
932
|
});
|
|
1292
|
-
// 3. Pause a bit to allow other macrotasks to run
|
|
1293
933
|
await new Promise((resolve) => {
|
|
1294
934
|
setTimeout(resolve, Math.min(timeout, 10));
|
|
1295
935
|
});
|
|
1296
936
|
}
|
|
1297
937
|
}
|
|
1298
|
-
//# sourceMappingURL=matterNode.js.map
|