matterbridge 3.5.2 → 3.5.3-dev-20260202-e19e9b6
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 +30 -1
- package/README-DOCKER.md +2 -2
- package/README.md +14 -9
- package/dist/broadcastServer.d.ts +0 -115
- package/dist/broadcastServer.js +0 -117
- package/dist/broadcastServerTypes.d.ts +0 -43
- package/dist/broadcastServerTypes.js +0 -24
- package/dist/checkUpdates.d.ts +0 -75
- package/dist/checkUpdates.js +1 -91
- 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/frontend.d.ts +0 -187
- package/dist/frontend.js +37 -498
- package/dist/frontendTypes.d.ts +0 -57
- package/dist/frontendTypes.js +0 -45
- package/dist/helpers.d.ts +0 -43
- package/dist/helpers.js +0 -54
- package/dist/index.d.ts +0 -23
- package/dist/index.js +0 -25
- package/dist/jestutils/export.d.ts +0 -1
- package/dist/jestutils/export.js +0 -1
- package/dist/jestutils/jestHelpers.d.ts +0 -255
- package/dist/jestutils/jestHelpers.js +15 -371
- package/dist/logger/export.d.ts +0 -1
- package/dist/logger/export.js +0 -1
- 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 -359
- package/dist/matterbridge.d.ts +0 -373
- package/dist/matterbridge.js +46 -854
- 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 +54 -1507
- package/dist/matterbridgeEndpointHelpers.d.ts +0 -425
- package/dist/matterbridgeEndpointHelpers.js +20 -482
- 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 -472
- package/dist/matterbridgePlatformTypes.d.ts +0 -29
- package/dist/matterbridgePlatformTypes.js +0 -24
- package/dist/matterbridgeTypes.d.ts +0 -46
- package/dist/matterbridgeTypes.js +0 -26
- 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 -305
- package/dist/pluginManager.js +5 -342
- package/dist/shelly.d.ts +0 -157
- package/dist/shelly.js +7 -178
- package/dist/spawn.d.ts +0 -32
- package/dist/spawn.js +1 -71
- package/dist/storage/export.d.ts +0 -1
- package/dist/storage/export.js +0 -1
- package/dist/utils/export.d.ts +0 -1
- package/dist/utils/export.js +0 -1
- package/dist/worker.d.ts +0 -61
- package/dist/worker.js +4 -65
- package/dist/workerCheckUpdates.d.ts +0 -24
- package/dist/workerCheckUpdates.js +5 -36
- package/dist/workerGlobalPrefix.d.ts +0 -24
- package/dist/workerGlobalPrefix.js +5 -36
- package/dist/workerTypes.d.ts +0 -25
- package/dist/workerTypes.js +0 -24
- package/frontend/build/assets/index.js +4 -4
- package/frontend/build/assets/vendor_emotion.js +1 -1
- package/frontend/build/assets/vendor_lodash.js +1 -1
- package/frontend/build/assets/vendor_mdi.js +1 -1
- package/frontend/build/assets/vendor_mui.js +22 -22
- package/frontend/build/assets/vendor_node_modules.js +20 -20
- package/frontend/build/assets/vendor_notistack.js +2 -2
- package/frontend/build/assets/vendor_qrcode.js +1 -1
- package/frontend/build/assets/vendor_rjsf.js +8 -8
- package/frontend/build/index.html +1 -1
- package/frontend/package.json +48 -47
- package/npm-shrinkwrap.json +77 -47
- package/package.json +7 -7
- package/dist/broadcastServer.d.ts.map +0 -1
- package/dist/broadcastServer.js.map +0 -1
- package/dist/broadcastServerTypes.d.ts.map +0 -1
- package/dist/broadcastServerTypes.js.map +0 -1
- package/dist/checkUpdates.d.ts.map +0 -1
- package/dist/checkUpdates.js.map +0 -1
- 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/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/frontend.d.ts.map +0 -1
- package/dist/frontend.js.map +0 -1
- package/dist/frontendTypes.d.ts.map +0 -1
- package/dist/frontendTypes.js.map +0 -1
- package/dist/helpers.d.ts.map +0 -1
- package/dist/helpers.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.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/logger/export.d.ts.map +0 -1
- package/dist/logger/export.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/matterbridgePlatformTypes.d.ts.map +0 -1
- package/dist/matterbridgePlatformTypes.js.map +0 -1
- package/dist/matterbridgeTypes.d.ts.map +0 -1
- package/dist/matterbridgeTypes.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/shelly.d.ts.map +0 -1
- package/dist/shelly.js.map +0 -1
- package/dist/spawn.d.ts.map +0 -1
- package/dist/spawn.js.map +0 -1
- package/dist/storage/export.d.ts.map +0 -1
- package/dist/storage/export.js.map +0 -1
- package/dist/utils/export.d.ts.map +0 -1
- package/dist/utils/export.js.map +0 -1
- package/dist/worker.d.ts.map +0 -1
- package/dist/worker.js.map +0 -1
- package/dist/workerCheckUpdates.d.ts.map +0 -1
- package/dist/workerCheckUpdates.js.map +0 -1
- package/dist/workerGlobalPrefix.d.ts.map +0 -1
- package/dist/workerGlobalPrefix.js.map +0 -1
- package/dist/workerTypes.d.ts.map +0 -1
- package/dist/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 './matterbridgeTypes.js';
|
|
44
16
|
import { bridge } from './matterbridgeDeviceTypes.js';
|
|
@@ -46,48 +18,27 @@ import { BroadcastServer } from './broadcastServer.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,26 +136,18 @@ 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({ dir: path.join(this.matterbridge.matterbridgeDirectory, NODE_STORAGE_DIR), writeQueue: false, expiredInterval: undefined, logging: false });
|
|
237
|
-
// @ts-expect-error access private property
|
|
238
149
|
this.pluginManager.matterbridge.nodeContext = await this.pluginManager.matterbridge.nodeStorage.createStorage('matterbridge');
|
|
239
150
|
await this.pluginManager.loadFromStorage();
|
|
240
|
-
// Create Matter node for a server mode device
|
|
241
151
|
if (this.pluginName && this.device && this.device.deviceName) {
|
|
242
152
|
this.log.debug(`Creating MatterNode instance for server node device ${CYAN}${this.device.deviceName}${db}...`);
|
|
243
153
|
await this.createDeviceServerNode(this.pluginName, this.device);
|
|
@@ -248,7 +158,6 @@ export class MatterNode extends EventEmitter {
|
|
|
248
158
|
if (!this.pluginName) {
|
|
249
159
|
this.log.debug('Creating MatterNode instance for all plugins...');
|
|
250
160
|
await this.createMatterbridgeServerNode();
|
|
251
|
-
// Load all enabled plugins
|
|
252
161
|
this.log.debug('Loading all plugins...');
|
|
253
162
|
const loadPromises = [];
|
|
254
163
|
for (const plugin of this.pluginManager.array().filter((p) => p.enabled)) {
|
|
@@ -261,7 +170,6 @@ export class MatterNode extends EventEmitter {
|
|
|
261
170
|
}
|
|
262
171
|
else {
|
|
263
172
|
this.log.debug(`Creating MatterNode instance for plugin ${CYAN}${this.pluginName}${db}...`);
|
|
264
|
-
// Load only the specified plugin
|
|
265
173
|
this.log.debug(`Loading plugin ${CYAN}${this.pluginName}${db}...`);
|
|
266
174
|
await this.pluginManager.load(this.pluginName);
|
|
267
175
|
this.log.debug(`Loaded plugin ${CYAN}${this.pluginName}${db}`);
|
|
@@ -275,16 +183,13 @@ export class MatterNode extends EventEmitter {
|
|
|
275
183
|
if (!this.serverNode && !this.pluginName)
|
|
276
184
|
throw new Error('Matter server node not created yet. Call create() first.');
|
|
277
185
|
this.log.info('Starting MatterNode...');
|
|
278
|
-
// Start Matter node for a server mode device
|
|
279
186
|
if (this.pluginName && this.device && this.device.deviceName) {
|
|
280
|
-
// Start the server node
|
|
281
187
|
this.log.debug(`Starting MatterNode for server device ${this.pluginName}:${this.device.deviceName}...`);
|
|
282
188
|
await this.startServerNode();
|
|
283
189
|
this.log.debug(`Started MatterNode for server device ${this.pluginName}:${this.device.deviceName}`);
|
|
284
190
|
return;
|
|
285
191
|
}
|
|
286
192
|
if (!this.pluginName) {
|
|
287
|
-
// Start all loaded plugins
|
|
288
193
|
this.log.debug('Starting all plugins...');
|
|
289
194
|
const startPromises = [];
|
|
290
195
|
for (const plugin of this.pluginManager.array().filter((p) => p.enabled && p.loaded)) {
|
|
@@ -292,11 +197,9 @@ export class MatterNode extends EventEmitter {
|
|
|
292
197
|
}
|
|
293
198
|
await Promise.all(startPromises);
|
|
294
199
|
this.log.debug('Started all plugins');
|
|
295
|
-
// Start the server node
|
|
296
200
|
this.log.debug('Starting MatterNode for all plugins...');
|
|
297
201
|
await this.startServerNode();
|
|
298
202
|
this.log.debug('Started MatterNode for all plugins');
|
|
299
|
-
// Configure all loaded plugins
|
|
300
203
|
this.log.debug('Configuring all plugins...');
|
|
301
204
|
const configurePromises = [];
|
|
302
205
|
for (const plugin of this.pluginManager.array().filter((p) => p.enabled && p.started)) {
|
|
@@ -306,16 +209,12 @@ export class MatterNode extends EventEmitter {
|
|
|
306
209
|
this.log.debug('Configured all plugins');
|
|
307
210
|
}
|
|
308
211
|
else {
|
|
309
|
-
// Start the loaded plugin
|
|
310
212
|
await this.pluginManager.start(this.pluginName, 'Starting MatterNode');
|
|
311
|
-
// Start the server node
|
|
312
213
|
this.log.debug(`Starting MatterNode for plugin ${this.pluginName}...`);
|
|
313
214
|
await this.startServerNode();
|
|
314
215
|
this.log.debug(`Started MatterNode for plugin ${this.pluginName}`);
|
|
315
|
-
// Configure the plugin
|
|
316
216
|
await this.pluginManager.configure(this.pluginName);
|
|
317
217
|
}
|
|
318
|
-
// Start the dependant MatterNodes
|
|
319
218
|
this.log.debug(`Starting dependant MatterNodes...`);
|
|
320
219
|
for (const dependantMatterNode of this.dependantMatterNodes.values()) {
|
|
321
220
|
await dependantMatterNode.start();
|
|
@@ -328,15 +227,13 @@ export class MatterNode extends EventEmitter {
|
|
|
328
227
|
if (!this.serverNode)
|
|
329
228
|
throw new Error('Matter server node not created yet. Call create() first.');
|
|
330
229
|
this.log.info('Stopping MatterNode...');
|
|
331
|
-
// Stop Matter node for a server mode device
|
|
332
230
|
if (this.pluginName && this.device && this.device.deviceName) {
|
|
333
|
-
// Stop the server node
|
|
334
231
|
this.log.debug(`Stopping MatterNode for server device ${this.pluginName}:${this.device.deviceName}...`);
|
|
335
232
|
await this.stopServerNode();
|
|
336
233
|
this.serverNode = undefined;
|
|
337
234
|
this.aggregatorNode = undefined;
|
|
338
235
|
await this.stopMatterStorage();
|
|
339
|
-
await this.destroy(false);
|
|
236
|
+
await this.destroy(false);
|
|
340
237
|
this.log.debug(`Stopped MatterNode for server device ${this.pluginName}:${this.device.deviceName}`);
|
|
341
238
|
this.log.info('Stopped MatterNode');
|
|
342
239
|
await this.yieldToNode();
|
|
@@ -356,7 +253,6 @@ export class MatterNode extends EventEmitter {
|
|
|
356
253
|
await this.pluginManager.shutdown(this.pluginName, 'Stopping MatterNode');
|
|
357
254
|
this.log.debug(`Stopped plugin ${this.pluginName}`);
|
|
358
255
|
}
|
|
359
|
-
// Stop the dependant MatterNodes
|
|
360
256
|
this.log.debug(`Stopping dependant MatterNodes...`);
|
|
361
257
|
for (const dependantMatterNode of this.dependantMatterNodes.values()) {
|
|
362
258
|
await dependantMatterNode.stop();
|
|
@@ -369,46 +265,24 @@ export class MatterNode extends EventEmitter {
|
|
|
369
265
|
this.log.info('Stopped MatterNode');
|
|
370
266
|
await this.yieldToNode();
|
|
371
267
|
}
|
|
372
|
-
/**
|
|
373
|
-
* Creates a MatterLogger function to show the matter.js log messages in AnsiLogger (console and frontend).
|
|
374
|
-
* It also logs to file (matter.log) if fileLogger is true.
|
|
375
|
-
*
|
|
376
|
-
* @returns {Function} The MatterLogger function. \x1b[35m for violet \x1b[34m is blue
|
|
377
|
-
*/
|
|
378
268
|
createDestinationMatterLogger() {
|
|
379
|
-
this.matterLog.logNameColor = '\x1b[34m';
|
|
269
|
+
this.matterLog.logNameColor = '\x1b[34m';
|
|
380
270
|
if (this.matterbridge.matterFileLogger) {
|
|
381
271
|
this.matterLog.logFilePath = path.join(this.matterbridge.matterbridgeDirectory, MATTER_LOGGER_FILE);
|
|
382
272
|
}
|
|
383
273
|
return (text, message) => {
|
|
384
|
-
// 2024-08-21 08:55:19.488 DEBUG InteractionMessenger Sending DataReport chunk with 28 attributes and 0 events: 1004 bytes
|
|
385
274
|
const logger = text.slice(44, 44 + 20).trim();
|
|
386
275
|
const msg = text.slice(65);
|
|
387
276
|
this.matterLog.logName = logger;
|
|
388
277
|
this.matterLog.log(MatterLogLevel.names[message.level], msg);
|
|
389
278
|
};
|
|
390
279
|
}
|
|
391
|
-
/**
|
|
392
|
-
* Starts the matter storage with name Matterbridge and performs a backup.
|
|
393
|
-
*
|
|
394
|
-
* @returns {Promise<void>} - A promise that resolves when the storage is started.
|
|
395
|
-
*/
|
|
396
280
|
async startMatterStorage() {
|
|
397
|
-
// Setup Matter storage
|
|
398
281
|
this.log.info(`Starting matter node storage...`);
|
|
399
282
|
this.matterStorageService = this.environment.get(StorageService);
|
|
400
283
|
this.log.info(`Started matter node storage in ${CYAN}${this.matterStorageService.location}${nf}`);
|
|
401
|
-
// Backup matter storage since it is created/opened correctly
|
|
402
284
|
await this.backupMatterStorage(path.join(this.matterbridge.matterbridgeDirectory, MATTER_STORAGE_NAME), path.join(this.matterbridge.matterbridgeDirectory, MATTER_STORAGE_NAME + '.backup'));
|
|
403
285
|
}
|
|
404
|
-
/**
|
|
405
|
-
* Makes a backup copy of the specified matter storage directory.
|
|
406
|
-
*
|
|
407
|
-
* @param {string} storageName - The name of the storage directory to be backed up.
|
|
408
|
-
* @param {string} backupName - The name of the backup directory to be created.
|
|
409
|
-
* @private
|
|
410
|
-
* @returns {Promise<void>} A promise that resolves when the has been done.
|
|
411
|
-
*/
|
|
412
286
|
async backupMatterStorage(storageName, backupName) {
|
|
413
287
|
this.log.info(`Creating matter node storage backup from ${CYAN}${storageName}${nf} to ${CYAN}${backupName}${nf}...`);
|
|
414
288
|
try {
|
|
@@ -416,7 +290,6 @@ export class MatterNode extends EventEmitter {
|
|
|
416
290
|
this.log.info('Created matter node storage backup');
|
|
417
291
|
}
|
|
418
292
|
catch (error) {
|
|
419
|
-
// istanbul ignore next if
|
|
420
293
|
if (error instanceof Error && error?.code === 'ENOENT') {
|
|
421
294
|
this.log.info(`No matter node storage found to backup from ${CYAN}${storageName}${nf} to ${CYAN}${backupName}${nf}`);
|
|
422
295
|
}
|
|
@@ -425,11 +298,6 @@ export class MatterNode extends EventEmitter {
|
|
|
425
298
|
}
|
|
426
299
|
}
|
|
427
300
|
}
|
|
428
|
-
/**
|
|
429
|
-
* Stops the matter storage.
|
|
430
|
-
*
|
|
431
|
-
* @returns {Promise<void>} A promise that resolves when the storage is stopped.
|
|
432
|
-
*/
|
|
433
301
|
async stopMatterStorage() {
|
|
434
302
|
this.log.info('Closing matter node storage...');
|
|
435
303
|
await this.matterStorageManager?.close();
|
|
@@ -439,21 +307,6 @@ export class MatterNode extends EventEmitter {
|
|
|
439
307
|
this.log.info('Closed matter node storage');
|
|
440
308
|
this.emit('closed');
|
|
441
309
|
}
|
|
442
|
-
/**
|
|
443
|
-
* Creates a server node storage context.
|
|
444
|
-
*
|
|
445
|
-
* @param {string} storeId - The storeId.
|
|
446
|
-
* @param {string} deviceName - The name of the device.
|
|
447
|
-
* @param {DeviceTypeId} deviceType - The device type of the device.
|
|
448
|
-
* @param {VendorId} vendorId - The vendor ID.
|
|
449
|
-
* @param {string} vendorName - The vendor name.
|
|
450
|
-
* @param {number} productId - The product ID.
|
|
451
|
-
* @param {string} productName - The product name.
|
|
452
|
-
* @param {string} [serialNumber] - The serial number of the device (optional).
|
|
453
|
-
* @param {string} [uniqueId] - The unique ID of the device (optional).
|
|
454
|
-
* @returns {Promise<StorageContext>} The storage context for the commissioning server.
|
|
455
|
-
* @throws {Error} If the storage service is not initialized.
|
|
456
|
-
*/
|
|
457
310
|
async createServerNodeContext(storeId, deviceName, deviceType, vendorId, vendorName, productId, productName, serialNumber, uniqueId) {
|
|
458
311
|
if (!this.matterStorageService) {
|
|
459
312
|
throw new Error('No storage service initialized');
|
|
@@ -496,52 +349,33 @@ export class MatterNode extends EventEmitter {
|
|
|
496
349
|
this.log.debug(`- hardwareVersionString: ${await storageContext.get('hardwareVersionString')}`);
|
|
497
350
|
return storageContext;
|
|
498
351
|
}
|
|
499
|
-
/**
|
|
500
|
-
* Creates a server node.
|
|
501
|
-
*
|
|
502
|
-
* @param {number} [port] - The port number for the server node. Defaults to 5540.
|
|
503
|
-
* @param {number} [passcode] - The passcode for the server node. Defaults to 20242025.
|
|
504
|
-
* @param {number} [discriminator] - The discriminator for the server node. Defaults to 3850.
|
|
505
|
-
* @returns {Promise<ServerNode<ServerNode.RootEndpoint>>} A promise that resolves to the created server node.
|
|
506
|
-
* @throws {Error} If the matter storage context is not created yet.
|
|
507
|
-
*/
|
|
508
352
|
async createServerNode(port = 5540, passcode = 20252026, discriminator = 3850) {
|
|
509
353
|
if (!this.matterStorageContext) {
|
|
510
354
|
throw new Error('Matter server node context not created yet. Call createServerNodeContext() first.');
|
|
511
355
|
}
|
|
512
356
|
const storeId = await this.matterStorageContext.get('storeId');
|
|
513
357
|
this.log.notice(`Creating server node for ${storeId} on port ${port} with passcode ${passcode} and discriminator ${discriminator}...`);
|
|
514
|
-
/**
|
|
515
|
-
* Create a Matter ServerNode, which contains the Root Endpoint and all relevant data and configuration
|
|
516
|
-
*/
|
|
517
358
|
const serverNode = await ServerNode.create({
|
|
518
|
-
// Required: Give the Node a unique ID which is used to store the state of this node
|
|
519
359
|
id: storeId,
|
|
520
|
-
// Provide the environment to run this node in
|
|
521
360
|
environment: this.environment,
|
|
522
|
-
// Provide Network relevant configuration like the port
|
|
523
361
|
network: {
|
|
524
362
|
listeningAddressIpv4: this.ipv4Address,
|
|
525
363
|
listeningAddressIpv6: this.ipv6Address,
|
|
526
364
|
port,
|
|
527
365
|
},
|
|
528
|
-
// Provide the certificate for the device
|
|
529
366
|
operationalCredentials: {
|
|
530
367
|
certification: this.certification,
|
|
531
368
|
},
|
|
532
|
-
// Provide Commissioning relevant settings
|
|
533
369
|
commissioning: {
|
|
534
370
|
passcode,
|
|
535
371
|
discriminator,
|
|
536
372
|
},
|
|
537
|
-
// Provide Node announcement settings
|
|
538
373
|
productDescription: {
|
|
539
374
|
name: await this.matterStorageContext.get('deviceName'),
|
|
540
375
|
deviceType: DeviceTypeId(await this.matterStorageContext.get('deviceType')),
|
|
541
376
|
vendorId: VendorId(await this.matterStorageContext.get('vendorId')),
|
|
542
377
|
productId: await this.matterStorageContext.get('productId'),
|
|
543
378
|
},
|
|
544
|
-
// Provide defaults for the BasicInformation cluster on the Root endpoint
|
|
545
379
|
basicInformation: {
|
|
546
380
|
vendorId: VendorId(await this.matterStorageContext.get('vendorId')),
|
|
547
381
|
vendorName: await this.matterStorageContext.get('vendorName'),
|
|
@@ -558,23 +392,17 @@ export class MatterNode extends EventEmitter {
|
|
|
558
392
|
reachable: true,
|
|
559
393
|
},
|
|
560
394
|
});
|
|
561
|
-
/**
|
|
562
|
-
* This event is triggered when the device is initially commissioned successfully.
|
|
563
|
-
* This means: It is added to the first fabric.
|
|
564
|
-
*/
|
|
565
395
|
serverNode.lifecycle.commissioned.on(() => {
|
|
566
396
|
this.log.notice(`Server node for ${storeId} was initially commissioned successfully!`);
|
|
567
397
|
this.advertisingNodes.delete(storeId);
|
|
568
398
|
this.server.request({ type: 'frontend_refreshrequired', src: 'matter', dst: 'frontend', params: { changed: 'matter', matter: { ...this.getServerNodeData(serverNode) } } });
|
|
569
399
|
});
|
|
570
|
-
/** This event is triggered when all fabrics are removed from the device, usually it also does a factory reset then. */
|
|
571
400
|
serverNode.lifecycle.decommissioned.on(() => {
|
|
572
401
|
this.log.notice(`Server node for ${storeId} was fully decommissioned successfully!`);
|
|
573
402
|
this.advertisingNodes.delete(storeId);
|
|
574
403
|
this.server.request({ type: 'frontend_refreshrequired', src: 'matter', dst: 'frontend', params: { changed: 'matter', matter: { ...this.getServerNodeData(serverNode) } } });
|
|
575
404
|
this.server.request({ type: 'frontend_snackbarmessage', src: 'matter', dst: 'frontend', params: { message: `${storeId} is offline`, timeout: 5, severity: 'warning' } });
|
|
576
405
|
});
|
|
577
|
-
/** This event is triggered when the device went online. This means that it is discoverable in the network. */
|
|
578
406
|
serverNode.lifecycle.online.on(async () => {
|
|
579
407
|
this.log.notice(`Server node for ${storeId} is online`);
|
|
580
408
|
if (!serverNode.lifecycle.isCommissioned) {
|
|
@@ -592,7 +420,6 @@ export class MatterNode extends EventEmitter {
|
|
|
592
420
|
this.server.request({ type: 'frontend_snackbarmessage', src: 'matter', dst: 'frontend', params: { message: `${storeId} is online`, timeout: 5, severity: 'success' } });
|
|
593
421
|
this.emit('online', storeId);
|
|
594
422
|
});
|
|
595
|
-
/** This event is triggered when the device went offline. it is not longer discoverable or connectable in the network. */
|
|
596
423
|
serverNode.lifecycle.offline.on(() => {
|
|
597
424
|
this.log.notice(`Server node for ${storeId} is offline`);
|
|
598
425
|
this.advertisingNodes.delete(storeId);
|
|
@@ -600,15 +427,11 @@ export class MatterNode extends EventEmitter {
|
|
|
600
427
|
this.server.request({ type: 'frontend_snackbarmessage', src: 'matter', dst: 'frontend', params: { message: `${storeId} is offline`, timeout: 5, severity: 'warning' } });
|
|
601
428
|
this.emit('offline', storeId);
|
|
602
429
|
});
|
|
603
|
-
/**
|
|
604
|
-
* This event is triggered when a fabric is added, removed or updated on the device. Use this if more granular
|
|
605
|
-
* information is needed.
|
|
606
|
-
*/
|
|
607
430
|
serverNode.events.commissioning.fabricsChanged.on((fabricIndex, fabricAction) => {
|
|
608
431
|
let action = '';
|
|
609
432
|
switch (fabricAction) {
|
|
610
433
|
case 'added':
|
|
611
|
-
this.advertisingNodes.delete(storeId);
|
|
434
|
+
this.advertisingNodes.delete(storeId);
|
|
612
435
|
action = 'added';
|
|
613
436
|
break;
|
|
614
437
|
case 'deleted':
|
|
@@ -621,22 +444,14 @@ export class MatterNode extends EventEmitter {
|
|
|
621
444
|
this.log.notice(`Commissioned fabric index ${fabricIndex} ${action} on server node for ${storeId}: ${debugStringify(serverNode.state.commissioning.fabrics[fabricIndex])}`);
|
|
622
445
|
this.server.request({ type: 'frontend_refreshrequired', src: 'matter', dst: 'frontend', params: { changed: 'matter', matter: { ...this.getServerNodeData(serverNode) } } });
|
|
623
446
|
});
|
|
624
|
-
/**
|
|
625
|
-
* This event is triggered when an operative new session was opened by a Controller.
|
|
626
|
-
* It is not triggered for the initial commissioning process, just afterwards for real connections.
|
|
627
|
-
*/
|
|
628
447
|
serverNode.events.sessions.opened.on((session) => {
|
|
629
448
|
this.log.notice(`Session opened on server node for ${storeId}: ${debugStringify(session)}`);
|
|
630
449
|
this.server.request({ type: 'frontend_refreshrequired', src: 'matter', dst: 'frontend', params: { changed: 'matter', matter: { ...this.getServerNodeData(serverNode) } } });
|
|
631
450
|
});
|
|
632
|
-
/**
|
|
633
|
-
* This event is triggered when an operative session is closed by a Controller or because the Device goes offline.
|
|
634
|
-
*/
|
|
635
451
|
serverNode.events.sessions.closed.on((session) => {
|
|
636
452
|
this.log.notice(`Session closed on server node for ${storeId}: ${debugStringify(session)}`);
|
|
637
453
|
this.server.request({ type: 'frontend_refreshrequired', src: 'matter', dst: 'frontend', params: { changed: 'matter', matter: { ...this.getServerNodeData(serverNode) } } });
|
|
638
454
|
});
|
|
639
|
-
/** This event is triggered when a subscription gets added or removed on an operative session. */
|
|
640
455
|
serverNode.events.sessions.subscriptionsChanged.on((session) => {
|
|
641
456
|
this.log.notice(`Session subscriptions changed on server node for ${storeId}: ${debugStringify(session)}`);
|
|
642
457
|
this.server.request({ type: 'frontend_refreshrequired', src: 'matter', dst: 'frontend', params: { changed: 'matter', matter: { ...this.getServerNodeData(serverNode) } } });
|
|
@@ -645,12 +460,6 @@ export class MatterNode extends EventEmitter {
|
|
|
645
460
|
this.log.info(`Created server node for ${this.storeId}`);
|
|
646
461
|
return serverNode;
|
|
647
462
|
}
|
|
648
|
-
/**
|
|
649
|
-
* Gets the matter serializable data of the specified server node.
|
|
650
|
-
*
|
|
651
|
-
* @param {ServerNode} [serverNode] - The server node to start.
|
|
652
|
-
* @returns {ApiMatter} The serializable data of the server node.
|
|
653
|
-
*/
|
|
654
463
|
getServerNodeData(serverNode) {
|
|
655
464
|
const advertiseTime = this.advertisingNodes.get(serverNode.id) || 0;
|
|
656
465
|
return {
|
|
@@ -667,13 +476,6 @@ export class MatterNode extends EventEmitter {
|
|
|
667
476
|
serialNumber: serverNode.state.basicInformation.serialNumber,
|
|
668
477
|
};
|
|
669
478
|
}
|
|
670
|
-
/**
|
|
671
|
-
* Starts the specified server node.
|
|
672
|
-
*
|
|
673
|
-
* @param {number} [timeout] - The timeout in milliseconds for starting the server node. Defaults to 30 seconds.
|
|
674
|
-
* @returns {Promise<void>} A promise that resolves when the server node has started.
|
|
675
|
-
* @throws {Error} If the server node is not created yet.
|
|
676
|
-
*/
|
|
677
479
|
async startServerNode(timeout = 30000) {
|
|
678
480
|
if (!this.serverNode) {
|
|
679
481
|
throw new Error('Matter server node not created yet. Call create() first.');
|
|
@@ -684,17 +486,9 @@ export class MatterNode extends EventEmitter {
|
|
|
684
486
|
this.log.notice(`Started ${this.serverNode.id} server node`);
|
|
685
487
|
}
|
|
686
488
|
catch (error) {
|
|
687
|
-
// istanbul ignore next
|
|
688
489
|
this.log.error(`Failed to start ${this.serverNode.id} server node: ${error instanceof Error ? error.message : error}`);
|
|
689
490
|
}
|
|
690
491
|
}
|
|
691
|
-
/**
|
|
692
|
-
* Stops the specified server node.
|
|
693
|
-
*
|
|
694
|
-
* @param {number} [timeout] - The timeout in milliseconds for stopping the server node. Defaults to 30 seconds.
|
|
695
|
-
* @returns {Promise<void>} A promise that resolves when the server node has stopped.
|
|
696
|
-
* @throws {Error} If the server node is not created yet.
|
|
697
|
-
*/
|
|
698
492
|
async stopServerNode(timeout = 30000) {
|
|
699
493
|
if (!this.serverNode) {
|
|
700
494
|
throw new Error('Matter server node not created yet. Call create() first.');
|
|
@@ -705,16 +499,9 @@ export class MatterNode extends EventEmitter {
|
|
|
705
499
|
this.log.info(`Closed ${this.serverNode.id} server node`);
|
|
706
500
|
}
|
|
707
501
|
catch (error) {
|
|
708
|
-
// istanbul ignore next
|
|
709
502
|
this.log.error(`Failed to close ${this.serverNode.id} server node: ${error instanceof Error ? error.message : error}`);
|
|
710
503
|
}
|
|
711
504
|
}
|
|
712
|
-
/**
|
|
713
|
-
* Creates an aggregator node with the specified storage context.
|
|
714
|
-
*
|
|
715
|
-
* @returns {Promise<Endpoint<AggregatorEndpoint>>} A promise that resolves to the created aggregator node.
|
|
716
|
-
* @throws {Error} If the matter storage context is not created yet.
|
|
717
|
-
*/
|
|
718
505
|
async createAggregatorNode() {
|
|
719
506
|
if (!this.matterStorageContext) {
|
|
720
507
|
throw new Error('Matter server node context not created yet. Call createServerNodeContext() first.');
|
|
@@ -724,16 +511,9 @@ export class MatterNode extends EventEmitter {
|
|
|
724
511
|
this.log.info(`Created ${await this.matterStorageContext.get('storeId')} aggregator`);
|
|
725
512
|
return aggregatorNode;
|
|
726
513
|
}
|
|
727
|
-
/**
|
|
728
|
-
* Creates the matterbridge server node.
|
|
729
|
-
*
|
|
730
|
-
* @returns {Promise<ServerNode<ServerNode.RootEndpoint>>} A promise that resolves to the created matterbridge server node.
|
|
731
|
-
*/
|
|
732
514
|
async createMatterbridgeServerNode() {
|
|
733
515
|
this.log.debug(`Creating ${plg}Matterbridge${db} server node...`);
|
|
734
|
-
this.matterStorageContext = await this.createServerNodeContext('Matterbridge',
|
|
735
|
-
'Matterbridge', // deviceName
|
|
736
|
-
this.aggregatorDeviceType, this.aggregatorVendorId, this.aggregatorVendorName, this.aggregatorProductId, this.aggregatorProductName, this.aggregatorSerialNumber, this.aggregatorUniqueId);
|
|
516
|
+
this.matterStorageContext = await this.createServerNodeContext('Matterbridge', 'Matterbridge', this.aggregatorDeviceType, this.aggregatorVendorId, this.aggregatorVendorName, this.aggregatorProductId, this.aggregatorProductName, this.aggregatorSerialNumber, this.aggregatorUniqueId);
|
|
737
517
|
this.serverNode = await this.createServerNode(this.port ? this.port++ : undefined, this.passcode ? this.passcode++ : undefined, this.discriminator ? this.discriminator++ : undefined);
|
|
738
518
|
this.aggregatorNode = await this.createAggregatorNode();
|
|
739
519
|
this.log.debug(`Adding ${plg}Matterbridge${db} aggregator node...`);
|
|
@@ -744,13 +524,6 @@ export class MatterNode extends EventEmitter {
|
|
|
744
524
|
this.log.debug(`Created ${plg}Matterbridge${db} server node`);
|
|
745
525
|
return this.serverNode;
|
|
746
526
|
}
|
|
747
|
-
/**
|
|
748
|
-
* Creates and configures the server node for an accessory plugin for a given device.
|
|
749
|
-
*
|
|
750
|
-
* @param {Plugin | PluginName} plugin - The plugin to configure.
|
|
751
|
-
* @param {MatterbridgeEndpoint} device - The device to associate with the plugin.
|
|
752
|
-
* @returns {Promise<ServerNode<ServerNode.RootEndpoint> | undefined>} A promise that resolves to the server node for the accessory plugin.
|
|
753
|
-
*/
|
|
754
527
|
async createAccessoryPlugin(plugin, device) {
|
|
755
528
|
if (typeof plugin === 'string') {
|
|
756
529
|
const _plugin = this.pluginManager.get(plugin);
|
|
@@ -772,12 +545,6 @@ export class MatterNode extends EventEmitter {
|
|
|
772
545
|
}
|
|
773
546
|
return this.serverNode;
|
|
774
547
|
}
|
|
775
|
-
/**
|
|
776
|
-
* Creates and configures the server node and the aggregator node for a dynamic plugin.
|
|
777
|
-
*
|
|
778
|
-
* @param {Plugin | PluginName} plugin - The plugin to configure.
|
|
779
|
-
* @returns {Promise<ServerNode<ServerNode.RootEndpoint> | undefined>} A promise that resolves to the server node for the dynamic plugin.
|
|
780
|
-
*/
|
|
781
548
|
async createDynamicPlugin(plugin) {
|
|
782
549
|
if (typeof plugin === 'string') {
|
|
783
550
|
const _plugin = this.pluginManager.get(plugin);
|
|
@@ -801,13 +568,6 @@ export class MatterNode extends EventEmitter {
|
|
|
801
568
|
}
|
|
802
569
|
return this.serverNode;
|
|
803
570
|
}
|
|
804
|
-
/**
|
|
805
|
-
* Creates and configures the server node for a single not bridged device.
|
|
806
|
-
*
|
|
807
|
-
* @param {Plugin | PluginName} plugin - The plugin to configure.
|
|
808
|
-
* @param {MatterbridgeEndpoint} device - The device to associate with the plugin.
|
|
809
|
-
* @returns {Promise<ServerNode<ServerNode.RootEndpoint> | undefined>} A promise that resolves to the server node for the device with mode server.
|
|
810
|
-
*/
|
|
811
571
|
async createDeviceServerNode(plugin, device) {
|
|
812
572
|
if (typeof plugin === 'string') {
|
|
813
573
|
const _plugin = this.pluginManager.get(plugin);
|
|
@@ -828,22 +588,13 @@ export class MatterNode extends EventEmitter {
|
|
|
828
588
|
}
|
|
829
589
|
return this.serverNode;
|
|
830
590
|
}
|
|
831
|
-
/**
|
|
832
|
-
* Adds a MatterbridgeEndpoint to the specified plugin.
|
|
833
|
-
*
|
|
834
|
-
* @param {string} pluginName - The name of the plugin.
|
|
835
|
-
* @param {MatterbridgeEndpoint} device - The device to add as a bridged endpoint.
|
|
836
|
-
* @returns {Promise<MatterbridgeEndpoint | undefined>} A promise that resolves to the added bridged endpoint, or undefined if there was an error.
|
|
837
|
-
*/
|
|
838
591
|
async addBridgedEndpoint(pluginName, device) {
|
|
839
|
-
// Check if the plugin is registered
|
|
840
592
|
const plugin = this.pluginManager.get(pluginName);
|
|
841
593
|
if (!plugin)
|
|
842
594
|
throw new Error(`Error adding bridged endpoint ${plg}${pluginName}${er}:${dev}${device.deviceName}${er} (${zb}${device.name}${er}): plugin not found`);
|
|
843
595
|
if (device.mode === 'server') {
|
|
844
596
|
try {
|
|
845
597
|
this.log.debug(`Creating MatterNode for device ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} (${zb}${device.name}${db})...`);
|
|
846
|
-
// Create the MatterNode to manage the device
|
|
847
598
|
const matterNode = new MatterNode(this.matterbridge, pluginName, device);
|
|
848
599
|
matterNode.port = this.port ? this.port++ : undefined;
|
|
849
600
|
matterNode.passcode = this.passcode ? this.passcode++ : undefined;
|
|
@@ -859,7 +610,6 @@ export class MatterNode extends EventEmitter {
|
|
|
859
610
|
}
|
|
860
611
|
else if (this.matterbridge.bridgeMode === 'bridge') {
|
|
861
612
|
if (device.mode === 'matter') {
|
|
862
|
-
// Register and add the device to the Matter server node
|
|
863
613
|
this.log.debug(`Adding matter endpoint ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} (${zb}${device.name}${db})...`);
|
|
864
614
|
if (!this.serverNode)
|
|
865
615
|
throw new Error(`Server node not found for matter endpoint ${plg}${pluginName}${er}:${dev}${device.deviceName}${er} (${zb}${device.name}${er})`);
|
|
@@ -872,7 +622,6 @@ export class MatterNode extends EventEmitter {
|
|
|
872
622
|
}
|
|
873
623
|
}
|
|
874
624
|
else {
|
|
875
|
-
// Register and add the device to the Matter aggregator node
|
|
876
625
|
this.log.debug(`Adding bridged endpoint ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} (${zb}${device.name}${db})...`);
|
|
877
626
|
if (!this.aggregatorNode)
|
|
878
627
|
throw new Error(`Aggregator node not found for endpoint ${plg}${pluginName}${er}:${dev}${device.deviceName}${er} (${zb}${device.name}${er})`);
|
|
@@ -886,7 +635,6 @@ export class MatterNode extends EventEmitter {
|
|
|
886
635
|
}
|
|
887
636
|
}
|
|
888
637
|
else if (this.matterbridge.bridgeMode === 'childbridge') {
|
|
889
|
-
// Register and add the device to the plugin server node
|
|
890
638
|
if (plugin.type === 'AccessoryPlatform') {
|
|
891
639
|
try {
|
|
892
640
|
this.log.debug(`Adding accessory endpoint ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} (${zb}${device.name}${db})...`);
|
|
@@ -902,12 +650,10 @@ export class MatterNode extends EventEmitter {
|
|
|
902
650
|
return;
|
|
903
651
|
}
|
|
904
652
|
}
|
|
905
|
-
// Register and add the device to the plugin aggregator node
|
|
906
653
|
if (plugin.type === 'DynamicPlatform') {
|
|
907
654
|
try {
|
|
908
655
|
this.log.debug(`Adding bridged endpoint ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} (${zb}${device.name}${db})...`);
|
|
909
656
|
if (!this.serverNode) {
|
|
910
|
-
// Fast plugins can add another device before the server node is ready, so we wait for the server node to be ready
|
|
911
657
|
await this.createDynamicPlugin(plugin);
|
|
912
658
|
}
|
|
913
659
|
if (device.mode === 'matter')
|
|
@@ -923,30 +669,19 @@ export class MatterNode extends EventEmitter {
|
|
|
923
669
|
}
|
|
924
670
|
if (plugin.registeredDevices !== undefined)
|
|
925
671
|
plugin.registeredDevices++;
|
|
926
|
-
// Add the device to the DeviceManager
|
|
927
672
|
await device.construction.ready;
|
|
928
673
|
await this.server.fetch({ type: 'devices_set', src: this.server.name, dst: 'devices', params: { device: toBaseDevice(device) } });
|
|
929
|
-
// Subscribe to the attributes changed event
|
|
930
674
|
await this.subscribeAttributeChanged(plugin, device);
|
|
931
675
|
this.log.info(`Added endpoint #${plugin.registeredDevices} ${plg}${pluginName}${nf}:${dev}${device.deviceName}${nf} (${zb}${device.name}${nf})`);
|
|
932
676
|
await this.yieldToNode(10);
|
|
933
677
|
return device;
|
|
934
678
|
}
|
|
935
|
-
/**
|
|
936
|
-
* Removes a MatterbridgeEndpoint from the specified plugin.
|
|
937
|
-
*
|
|
938
|
-
* @param {string} pluginName - The name of the plugin.
|
|
939
|
-
* @param {MatterbridgeEndpoint} device - The device to remove as a bridged endpoint.
|
|
940
|
-
* @returns {Promise<MatterbridgeEndpoint | undefined>} A promise that resolves to the removed bridged endpoint, or undefined if there was an error.
|
|
941
|
-
*/
|
|
942
679
|
async removeBridgedEndpoint(pluginName, device) {
|
|
943
680
|
this.log.debug(`Removing bridged endpoint ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} (${zb}${device.name}${db})...`);
|
|
944
|
-
// Check if the plugin is registered
|
|
945
681
|
const plugin = this.pluginManager.get(pluginName);
|
|
946
682
|
if (!plugin)
|
|
947
683
|
throw new Error(`Error removing bridged endpoint ${plg}${pluginName}${er}:${dev}${device.deviceName}${er} (${zb}${device.name}${er}): plugin not found`);
|
|
948
684
|
if (device.serverNode) {
|
|
949
|
-
// TODO: Close and remove the MatterNode managing the device
|
|
950
685
|
}
|
|
951
686
|
else if (this.matterbridge.bridgeMode === 'bridge') {
|
|
952
687
|
if (!this.aggregatorNode)
|
|
@@ -968,25 +703,11 @@ export class MatterNode extends EventEmitter {
|
|
|
968
703
|
this.log.info(`Removed bridged endpoint #${plugin.registeredDevices} ${plg}${pluginName}${nf}:${dev}${device.deviceName}${nf} (${zb}${device.name}${nf})`);
|
|
969
704
|
if (plugin.registeredDevices !== undefined)
|
|
970
705
|
plugin.registeredDevices--;
|
|
971
|
-
// Remove the device from the DeviceManager
|
|
972
706
|
await this.server.fetch({ type: 'devices_remove', src: this.server.name, dst: 'devices', params: { device: toBaseDevice(device) } });
|
|
973
707
|
await this.yieldToNode(10);
|
|
974
708
|
return device;
|
|
975
709
|
}
|
|
976
|
-
/**
|
|
977
|
-
* Removes all bridged endpoints from the specified plugin.
|
|
978
|
-
*
|
|
979
|
-
* @param {string} pluginName - The name of the plugin.
|
|
980
|
-
* @param {number} [delay] - The delay in milliseconds between removing each bridged endpoint (default: 0).
|
|
981
|
-
* @returns {Promise<void>} A promise that resolves when all bridged endpoints have been removed.
|
|
982
|
-
*
|
|
983
|
-
* @remarks
|
|
984
|
-
* This method iterates through all devices in the DeviceManager and removes each bridged endpoint associated with the specified plugin.
|
|
985
|
-
* It also applies a delay between each removal if specified.
|
|
986
|
-
* The delay is useful to allow the controllers to receive a single subscription for each device removed.
|
|
987
|
-
*/
|
|
988
710
|
async removeAllBridgedEndpoints(pluginName, delay = 0) {
|
|
989
|
-
// Check if the plugin is registered
|
|
990
711
|
const plugin = this.pluginManager.get(pluginName);
|
|
991
712
|
if (!plugin)
|
|
992
713
|
throw new Error(`Error removing all bridged endpoints for plugin ${plg}${pluginName}${er}: plugin not found`);
|
|
@@ -1001,7 +722,6 @@ export class MatterNode extends EventEmitter {
|
|
|
1001
722
|
this.log.info(`Removed bridged endpoint #${plugin.registeredDevices} ${plg}${pluginName}${nf}:${dev}${device.deviceName}${nf} (${zb}${endpoint?.name}${nf})`);
|
|
1002
723
|
if (plugin.registeredDevices !== undefined)
|
|
1003
724
|
plugin.registeredDevices--;
|
|
1004
|
-
// Remove the device from the DeviceManager
|
|
1005
725
|
await this.server.fetch({ type: 'devices_remove', src: this.server.name, dst: 'devices', params: { device: toBaseDevice(device) } });
|
|
1006
726
|
await this.yieldToNode(10);
|
|
1007
727
|
if (delay > 0)
|
|
@@ -1010,25 +730,6 @@ export class MatterNode extends EventEmitter {
|
|
|
1010
730
|
if (delay > 0)
|
|
1011
731
|
await wait(Number(process.env['MATTERBRIDGE_REMOVE_ALL_ENDPOINT_TIMEOUT_MS']) || 2000);
|
|
1012
732
|
}
|
|
1013
|
-
/**
|
|
1014
|
-
* Registers a virtual device with the Matterbridge platform.
|
|
1015
|
-
* Virtual devices are only supported in bridge mode and childbridge mode with a DynamicPlatform.
|
|
1016
|
-
*
|
|
1017
|
-
* The virtual device is created as an instance of `Endpoint` with the provided device type.
|
|
1018
|
-
* When the virtual device is turned on, the provided callback function is executed.
|
|
1019
|
-
* The onOff state of the virtual device always reverts to false when the device is turned on.
|
|
1020
|
-
*
|
|
1021
|
-
* @param {string} pluginName - The name of the plugin.
|
|
1022
|
-
* @param { string } name - The name of the virtual device.
|
|
1023
|
-
* @param { 'light' | 'outlet' | 'switch' | 'mounted_switch' } type - The type of the virtual device.
|
|
1024
|
-
* @param { () => Promise<void> } callback - The callback to call when the virtual device is turned on.
|
|
1025
|
-
*
|
|
1026
|
-
* @returns {Promise<boolean>} A promise that resolves to true if the virtual device was successfully registered, false otherwise.
|
|
1027
|
-
*
|
|
1028
|
-
* @remarks
|
|
1029
|
-
* The virtual devices don't show up in the device list of the frontend.
|
|
1030
|
-
* Type 'switch' is not supported by Alexa and 'mounted_switch' is not supported by Apple Home.
|
|
1031
|
-
*/
|
|
1032
733
|
async addVirtualEndpoint(pluginName, name, type, callback) {
|
|
1033
734
|
this.log.debug(`Creating virtual device ${plg}${pluginName}${db}:${dev}${name}${db}...`);
|
|
1034
735
|
const plugin = this.pluginManager.get(pluginName);
|
|
@@ -1053,20 +754,10 @@ export class MatterNode extends EventEmitter {
|
|
|
1053
754
|
await this.yieldToNode(10);
|
|
1054
755
|
return true;
|
|
1055
756
|
}
|
|
1056
|
-
/**
|
|
1057
|
-
* Subscribes to the attribute change event for the given device and plugin.
|
|
1058
|
-
* Specifically, it listens for changes in the 'reachable' attribute of the
|
|
1059
|
-
* BridgedDeviceBasicInformationServer cluster server of the bridged device or BasicInformationServer cluster server of server node.
|
|
1060
|
-
*
|
|
1061
|
-
* @param {Plugin} plugin - The plugin associated with the device.
|
|
1062
|
-
* @param {MatterbridgeEndpoint} device - The device to subscribe to attribute changes for.
|
|
1063
|
-
* @returns {Promise<void>} A promise that resolves when the subscription is set up.
|
|
1064
|
-
*/
|
|
1065
757
|
async subscribeAttributeChanged(plugin, device) {
|
|
1066
758
|
if (!plugin || !device || !device.plugin || !device.serialNumber || !device.uniqueId || !device.maybeNumber)
|
|
1067
759
|
return;
|
|
1068
760
|
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})`);
|
|
1069
|
-
// Subscribe to the reachable$Changed event of the BasicInformationServer cluster server of the server node in childbridge mode
|
|
1070
761
|
if (this.matterbridge.bridgeMode === 'childbridge' && plugin.type === 'AccessoryPlatform' && this.serverNode) {
|
|
1071
762
|
this.serverNode.eventsOf(BasicInformationServer).reachable$Changed?.on((reachable) => {
|
|
1072
763
|
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'}`);
|
|
@@ -1074,7 +765,6 @@ export class MatterNode extends EventEmitter {
|
|
|
1074
765
|
type: 'frontend_attributechanged',
|
|
1075
766
|
src: 'matter',
|
|
1076
767
|
dst: 'frontend',
|
|
1077
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
1078
768
|
params: { plugin: device.plugin, serialNumber: device.serialNumber, uniqueId: device.uniqueId, number: device.number, id: device.id, cluster: 'BasicInformation', attribute: 'reachable', value: reachable },
|
|
1079
769
|
});
|
|
1080
770
|
});
|
|
@@ -1127,7 +817,6 @@ export class MatterNode extends EventEmitter {
|
|
|
1127
817
|
type: 'frontend_attributechanged',
|
|
1128
818
|
src: 'matter',
|
|
1129
819
|
dst: 'frontend',
|
|
1130
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
1131
820
|
params: { plugin: device.plugin, serialNumber: device.serialNumber, uniqueId: device.uniqueId, number: device.number, id: device.id, cluster: sub.cluster, attribute: sub.attribute, value: value },
|
|
1132
821
|
});
|
|
1133
822
|
});
|
|
@@ -1141,7 +830,6 @@ export class MatterNode extends EventEmitter {
|
|
|
1141
830
|
type: 'frontend_attributechanged',
|
|
1142
831
|
src: 'matter',
|
|
1143
832
|
dst: 'frontend',
|
|
1144
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
1145
833
|
params: { plugin: device.plugin, serialNumber: device.serialNumber, uniqueId: device.uniqueId, number: child.number, id: child.id, cluster: sub.cluster, attribute: sub.attribute, value: value },
|
|
1146
834
|
});
|
|
1147
835
|
});
|
|
@@ -1149,12 +837,6 @@ export class MatterNode extends EventEmitter {
|
|
|
1149
837
|
}
|
|
1150
838
|
}
|
|
1151
839
|
}
|
|
1152
|
-
/**
|
|
1153
|
-
* Sanitizes the fabric information by converting bigint properties to strings because `res.json` doesn't support bigint.
|
|
1154
|
-
*
|
|
1155
|
-
* @param {ExposedFabricInformation[]} fabricInfo - The array of exposed fabric information objects.
|
|
1156
|
-
* @returns {SanitizedExposedFabricInformation[]} An array of sanitized exposed fabric information objects.
|
|
1157
|
-
*/
|
|
1158
840
|
sanitizeFabricInformations(fabricInfo) {
|
|
1159
841
|
return fabricInfo.map((info) => {
|
|
1160
842
|
return {
|
|
@@ -1168,12 +850,6 @@ export class MatterNode extends EventEmitter {
|
|
|
1168
850
|
};
|
|
1169
851
|
});
|
|
1170
852
|
}
|
|
1171
|
-
/**
|
|
1172
|
-
* Sanitizes the session information by converting bigint properties to strings because `res.json` doesn't support bigint.
|
|
1173
|
-
*
|
|
1174
|
-
* @param {SessionsBehavior.Session[]} sessions - The array of session information objects.
|
|
1175
|
-
* @returns {SanitizedSession[]} An array of sanitized session information objects.
|
|
1176
|
-
*/
|
|
1177
853
|
sanitizeSessionInformation(sessions) {
|
|
1178
854
|
return sessions
|
|
1179
855
|
.filter((session) => session.isPeerActive)
|
|
@@ -1200,21 +876,10 @@ export class MatterNode extends EventEmitter {
|
|
|
1200
876
|
};
|
|
1201
877
|
});
|
|
1202
878
|
}
|
|
1203
|
-
/**
|
|
1204
|
-
* Sets the reachability of the specified server node and trigger the corresponding event.
|
|
1205
|
-
*
|
|
1206
|
-
* @param {boolean} reachable - A boolean indicating the reachability status to set.
|
|
1207
|
-
*/
|
|
1208
879
|
async setServerReachability(reachable) {
|
|
1209
880
|
await this.serverNode?.setStateOf(BasicInformationServer, { reachable });
|
|
1210
881
|
this.serverNode?.act((agent) => this.serverNode?.eventsOf(BasicInformationServer).reachableChanged?.emit({ reachableNewValue: reachable }, agent.context));
|
|
1211
882
|
}
|
|
1212
|
-
/**
|
|
1213
|
-
* Sets the reachability of the specified aggregator node bridged devices and trigger.
|
|
1214
|
-
*
|
|
1215
|
-
* @param {Endpoint<AggregatorEndpoint>} aggregatorNode - The aggregator node to set the reachability for.
|
|
1216
|
-
* @param {boolean} reachable - A boolean indicating the reachability status to set.
|
|
1217
|
-
*/
|
|
1218
883
|
async setAggregatorReachability(aggregatorNode, reachable) {
|
|
1219
884
|
for (const child of aggregatorNode.parts) {
|
|
1220
885
|
this.log.debug(`Setting reachability of ${child?.deviceName} to ${reachable}`);
|
|
@@ -1260,35 +925,19 @@ export class MatterNode extends EventEmitter {
|
|
|
1260
925
|
case 0x1488:
|
|
1261
926
|
vendorName = '(ShortcutLabsFlic)';
|
|
1262
927
|
break;
|
|
1263
|
-
case 65521:
|
|
928
|
+
case 65521:
|
|
1264
929
|
vendorName = '(MatterTest)';
|
|
1265
930
|
break;
|
|
1266
931
|
}
|
|
1267
932
|
return vendorName;
|
|
1268
933
|
};
|
|
1269
|
-
/**
|
|
1270
|
-
* Yield to the Node.js event loop:
|
|
1271
|
-
* 1. Flushes the current microtask queue (Promise/async continuations queued so far).
|
|
1272
|
-
* 2. Yields one macrotask turn (setImmediate) and then its microtasks.
|
|
1273
|
-
* 3. Waits a bit (setTimeout) to allow other macrotasks to run.
|
|
1274
|
-
*
|
|
1275
|
-
* This does **not** guarantee that every promise in the process is settled,
|
|
1276
|
-
* but it gives all already-scheduled work a very good chance to run before continuing.
|
|
1277
|
-
*
|
|
1278
|
-
* @param {number} [timeout] - Optional timeout in milliseconds to wait after yielding. Default is 100 ms (minimum 10 ms).
|
|
1279
|
-
* @returns {Promise<void>}
|
|
1280
|
-
*/
|
|
1281
934
|
async yieldToNode(timeout = 100) {
|
|
1282
|
-
// 1. Let all currently queued microtasks run
|
|
1283
935
|
await Promise.resolve();
|
|
1284
|
-
// 2. Yield to the next event-loop turn (macrotask + its microtasks)
|
|
1285
936
|
await new Promise((resolve) => {
|
|
1286
937
|
setImmediate(resolve);
|
|
1287
938
|
});
|
|
1288
|
-
// 3. Pause a bit to allow other macrotasks to run
|
|
1289
939
|
await new Promise((resolve) => {
|
|
1290
940
|
setTimeout(resolve, Math.min(timeout, 10));
|
|
1291
941
|
});
|
|
1292
942
|
}
|
|
1293
943
|
}
|
|
1294
|
-
//# sourceMappingURL=matterNode.js.map
|