matterbridge 1.6.1 → 1.6.2
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 +35 -1
- package/README-DEV.md +0 -4
- package/README-NGINX.md +63 -0
- package/README.md +4 -0
- package/dist/cli.js +15 -7
- package/dist/cli.js.map +1 -1
- package/dist/deviceManager.d.ts +1 -1
- package/dist/deviceManager.d.ts.map +1 -1
- package/dist/deviceManager.js +1 -1
- package/dist/deviceManager.js.map +1 -1
- package/dist/index.d.ts +9 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +23 -10
- package/dist/index.js.map +1 -1
- package/dist/matter/export.d.ts +5 -0
- package/dist/matter/export.d.ts.map +1 -0
- package/dist/matter/export.js +5 -0
- package/dist/matter/export.js.map +1 -0
- package/dist/matterbridge.d.ts +12 -7
- package/dist/matterbridge.d.ts.map +1 -1
- package/dist/matterbridge.js +113 -83
- package/dist/matterbridge.js.map +1 -1
- package/dist/matterbridgeAccessoryPlatform.d.ts.map +1 -1
- package/dist/matterbridgeAccessoryPlatform.js.map +1 -1
- package/dist/matterbridgeBehaviors.d.ts +1123 -0
- package/dist/matterbridgeBehaviors.d.ts.map +1 -0
- package/dist/matterbridgeBehaviors.js +281 -0
- package/dist/matterbridgeBehaviors.js.map +1 -0
- package/dist/matterbridgeDevice.d.ts +2069 -1511
- package/dist/matterbridgeDevice.d.ts.map +1 -1
- package/dist/matterbridgeDevice.js +192 -196
- package/dist/matterbridgeDevice.js.map +1 -1
- package/dist/matterbridgeDeviceTypes.d.ts +58 -0
- package/dist/matterbridgeDeviceTypes.d.ts.map +1 -0
- package/dist/matterbridgeDeviceTypes.js +308 -0
- package/dist/matterbridgeDeviceTypes.js.map +1 -0
- package/dist/matterbridgeDynamicPlatform.d.ts.map +1 -1
- package/dist/matterbridgeDynamicPlatform.js.map +1 -1
- package/dist/matterbridgeEdge.d.ts +19 -20
- package/dist/matterbridgeEdge.d.ts.map +1 -1
- package/dist/matterbridgeEdge.js +505 -102
- package/dist/matterbridgeEdge.js.map +1 -1
- package/dist/matterbridgeEndpoint.d.ts +3544 -2304
- package/dist/matterbridgeEndpoint.d.ts.map +1 -1
- package/dist/matterbridgeEndpoint.js +671 -467
- package/dist/matterbridgeEndpoint.js.map +1 -1
- package/dist/matterbridgePlatform.d.ts +4 -3
- package/dist/matterbridgePlatform.d.ts.map +1 -1
- package/dist/matterbridgePlatform.js +10 -2
- package/dist/matterbridgePlatform.js.map +1 -1
- package/dist/matterbridgeTypes.d.ts +7 -8
- package/dist/matterbridgeTypes.d.ts.map +1 -1
- package/dist/matterbridgeTypes.js.map +1 -1
- package/dist/matterbridgeWebsocket.d.ts +1 -1
- package/dist/matterbridgeWebsocket.d.ts.map +1 -1
- package/dist/matterbridgeWebsocket.js +5 -3
- package/dist/matterbridgeWebsocket.js.map +1 -1
- package/dist/pluginManager.d.ts.map +1 -1
- package/dist/pluginManager.js +16 -7
- package/dist/pluginManager.js.map +1 -1
- package/dist/utils/colorUtils.js +1 -1
- package/dist/utils/colorUtils.js.map +1 -1
- package/dist/utils/utils.d.ts +21 -0
- package/dist/utils/utils.d.ts.map +1 -1
- package/dist/utils/utils.js +49 -3
- package/dist/utils/utils.js.map +1 -1
- package/frontend/build/asset-manifest.json +62 -6
- package/frontend/build/index.html +1 -1
- package/frontend/build/static/css/main.823e08b6.css +2 -0
- package/frontend/build/static/css/main.823e08b6.css.map +1 -0
- package/frontend/build/static/js/main.a14c87e7.js +115 -0
- package/frontend/build/static/js/{main.045d08f7.js.LICENSE.txt → main.a14c87e7.js.LICENSE.txt} +3 -3
- package/frontend/build/static/js/main.a14c87e7.js.map +1 -0
- package/frontend/build/static/media/roboto-cyrillic-300-normal.1b79538ccd585c259996.woff2 +0 -0
- package/frontend/build/static/media/roboto-cyrillic-300-normal.5f077fd7b977d1715acf.woff +0 -0
- package/frontend/build/static/media/roboto-cyrillic-400-normal.5d2930082227d172f62c.woff +0 -0
- package/frontend/build/static/media/roboto-cyrillic-400-normal.a9e19870cf6c4b973427.woff2 +0 -0
- package/frontend/build/static/media/roboto-cyrillic-500-normal.0ae2428323939af5e1ad.woff2 +0 -0
- package/frontend/build/static/media/roboto-cyrillic-500-normal.dd7bc8a52c6c70c5a3f5.woff +0 -0
- package/frontend/build/static/media/roboto-cyrillic-700-normal.3f6e1548bd5175a8c342.woff +0 -0
- package/frontend/build/static/media/roboto-cyrillic-700-normal.4fdfc29a10e7d4b7c527.woff2 +0 -0
- package/frontend/build/static/media/roboto-cyrillic-ext-300-normal.795dbc8140e3fef82983.woff +0 -0
- package/frontend/build/static/media/roboto-cyrillic-ext-300-normal.80947a31d23c70204b47.woff2 +0 -0
- package/frontend/build/static/media/roboto-cyrillic-ext-400-normal.135d076fa32aa0b4d105.woff +0 -0
- package/frontend/build/static/media/roboto-cyrillic-ext-400-normal.5cec61a21cc20180fbe1.woff2 +0 -0
- package/frontend/build/static/media/roboto-cyrillic-ext-500-normal.6de16332fda843a3dc3d.woff2 +0 -0
- package/frontend/build/static/media/roboto-cyrillic-ext-500-normal.c0a0638f90b31d6454ba.woff +0 -0
- package/frontend/build/static/media/roboto-cyrillic-ext-700-normal.4750292c47fa2bc6ac1a.woff2 +0 -0
- package/frontend/build/static/media/roboto-cyrillic-ext-700-normal.ca247189fc12d00de361.woff +0 -0
- package/frontend/build/static/media/roboto-greek-300-normal.285f3e6261d8eb20417d.woff2 +0 -0
- package/frontend/build/static/media/roboto-greek-300-normal.889beddda1c9bd9f97df.woff +0 -0
- package/frontend/build/static/media/roboto-greek-400-normal.160a791a8e4f46bca3cc.woff +0 -0
- package/frontend/build/static/media/roboto-greek-400-normal.2c32b1315be61477013a.woff2 +0 -0
- package/frontend/build/static/media/roboto-greek-500-normal.60810e07c7b0273013aa.woff +0 -0
- package/frontend/build/static/media/roboto-greek-500-normal.f95e757c5483310f9c11.woff2 +0 -0
- package/frontend/build/static/media/roboto-greek-700-normal.77dd370f2001e184ba0d.woff2 +0 -0
- package/frontend/build/static/media/roboto-greek-700-normal.df87b053fae3d7ad5f7a.woff +0 -0
- package/frontend/build/static/media/roboto-greek-ext-300-normal.b590dbe5c639944366d1.woff +0 -0
- package/frontend/build/static/media/roboto-greek-ext-300-normal.d6049cb54aa6fbe14c42.woff2 +0 -0
- package/frontend/build/static/media/roboto-greek-ext-400-normal.16eb83b4a3b1ea994243.woff +0 -0
- package/frontend/build/static/media/roboto-greek-ext-400-normal.1df4abad55796d11a0c8.woff2 +0 -0
- package/frontend/build/static/media/roboto-greek-ext-500-normal.4a96ba31abcce0f5d52b.woff2 +0 -0
- package/frontend/build/static/media/roboto-greek-ext-500-normal.fd28d9c008bf3af1bed7.woff +0 -0
- package/frontend/build/static/media/roboto-greek-ext-700-normal.2dd6febad11502dec6a6.woff2 +0 -0
- package/frontend/build/static/media/roboto-greek-ext-700-normal.4abdc9fff4507f17d726.woff +0 -0
- package/frontend/build/static/media/roboto-latin-300-normal.b850f1ff581ea232fac9.woff2 +0 -0
- package/frontend/build/static/media/roboto-latin-300-normal.c4bc0593c9954d79cb3a.woff +0 -0
- package/frontend/build/static/media/roboto-latin-400-normal.047a7839f69b209db815.woff +0 -0
- package/frontend/build/static/media/roboto-latin-400-normal.297d48e1b5a10c0831a9.woff2 +0 -0
- package/frontend/build/static/media/roboto-latin-500-normal.68d40d6d01c6f85d24ba.woff +0 -0
- package/frontend/build/static/media/roboto-latin-500-normal.7077203b1982951ecf76.woff2 +0 -0
- package/frontend/build/static/media/roboto-latin-700-normal.4535474e1cf8598695ad.woff2 +0 -0
- package/frontend/build/static/media/roboto-latin-700-normal.9f6a16a7770c87b2042b.woff +0 -0
- package/frontend/build/static/media/roboto-latin-ext-300-normal.14982a9e4857a93b6dce.woff +0 -0
- package/frontend/build/static/media/roboto-latin-ext-300-normal.97cbc447d4a8d41a9543.woff2 +0 -0
- package/frontend/build/static/media/roboto-latin-ext-400-normal.27da5b36b6d3a16f53f4.woff +0 -0
- package/frontend/build/static/media/roboto-latin-ext-400-normal.2eeae187764baf05867d.woff2 +0 -0
- package/frontend/build/static/media/roboto-latin-ext-500-normal.06c30711d588145a4541.woff +0 -0
- package/frontend/build/static/media/roboto-latin-ext-500-normal.9a18d7bb9ff7a6af7b32.woff2 +0 -0
- package/frontend/build/static/media/roboto-latin-ext-700-normal.18841836e391d39e83a8.woff2 +0 -0
- package/frontend/build/static/media/roboto-latin-ext-700-normal.3c5bcdd0e69c4c3ffafe.woff +0 -0
- package/frontend/build/static/media/roboto-vietnamese-300-normal.c96b16e5c05c7b7c3e89.woff2 +0 -0
- package/frontend/build/static/media/roboto-vietnamese-300-normal.f5e7cea32756dfe7af40.woff +0 -0
- package/frontend/build/static/media/roboto-vietnamese-400-normal.0dc97c66f9b542d6fa17.woff +0 -0
- package/frontend/build/static/media/roboto-vietnamese-400-normal.d3f8e26d6c27de8102b6.woff2 +0 -0
- package/frontend/build/static/media/roboto-vietnamese-500-normal.090fabef926bdc0e9b9f.woff2 +0 -0
- package/frontend/build/static/media/roboto-vietnamese-500-normal.23b7b8a2524d2d4b637b.woff +0 -0
- package/frontend/build/static/media/roboto-vietnamese-700-normal.0a79a9fabfc32e33f360.woff2 +0 -0
- package/frontend/build/static/media/roboto-vietnamese-700-normal.35ed0597568ff6f19c16.woff +0 -0
- package/npm-shrinkwrap.json +117 -36
- package/package.json +8 -3
- package/dist/matterbridgeController.d.ts +0 -24
- package/dist/matterbridgeController.d.ts.map +0 -1
- package/dist/matterbridgeController.js +0 -386
- package/dist/matterbridgeController.js.map +0 -1
- package/frontend/build/static/css/main.1cf003ae.css +0 -2
- package/frontend/build/static/css/main.1cf003ae.css.map +0 -1
- package/frontend/build/static/js/main.045d08f7.js +0 -3
- package/frontend/build/static/js/main.045d08f7.js.map +0 -1
package/dist/matterbridgeEdge.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
1
2
|
/**
|
|
2
3
|
* This file contains the class MatterbridgeEdge that extends the Matterbridge class.
|
|
3
4
|
*
|
|
@@ -21,28 +22,27 @@
|
|
|
21
22
|
* limitations under the License. *
|
|
22
23
|
*/
|
|
23
24
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
24
|
-
|
|
25
|
-
* Import needed modules from @project-chip/matter-node.js
|
|
26
|
-
*/
|
|
27
|
-
// Include this first to auto-register Crypto, Network and Time Node.js implementations
|
|
28
|
-
import '@project-chip/matter-node.js';
|
|
29
|
-
import { CryptoNode } from '@project-chip/matter-node.js/crypto';
|
|
30
|
-
import { DeviceTypeId, FabricIndex, VendorId } from '@project-chip/matter-node.js/datatype';
|
|
31
|
-
import { Format, Level } from '@project-chip/matter-node.js/log';
|
|
32
|
-
import { getParameter, hasParameter } from '@project-chip/matter-node.js/util';
|
|
33
|
-
import { Environment, StorageService } from '@project-chip/matter.js/environment';
|
|
34
|
-
import { ServerNode } from '@project-chip/matter.js/node';
|
|
35
|
-
import { FabricAction } from '@project-chip/matter-node.js/fabric';
|
|
36
|
-
import { Endpoint } from '@project-chip/matter.js/endpoint';
|
|
37
|
-
import { AggregatorEndpoint } from '@project-chip/matter.js/endpoints/AggregatorEndpoint';
|
|
38
|
-
// Other imports
|
|
39
|
-
import { Matterbridge } from './matterbridge.js';
|
|
40
|
-
import { rs, GREEN } from 'node-ansi-logger';
|
|
25
|
+
// Node.js modules
|
|
41
26
|
import path from 'path';
|
|
42
27
|
import os from 'os';
|
|
43
|
-
import {
|
|
44
|
-
|
|
45
|
-
|
|
28
|
+
import { randomBytes } from 'crypto';
|
|
29
|
+
// NodeStorage and AnsiLogger modules
|
|
30
|
+
import { rs, GREEN, debugStringify, er, zb, nf } from 'node-ansi-logger';
|
|
31
|
+
// Matterbridge
|
|
32
|
+
import { Matterbridge } from './matterbridge.js';
|
|
33
|
+
import { MatterbridgeEndpoint } from './matterbridgeEndpoint.js';
|
|
34
|
+
import { bridge, genericSwitch } from './matterbridgeDeviceTypes.js';
|
|
35
|
+
import { dev, plg } from './matterbridgeTypes.js';
|
|
36
|
+
import { copyDirectory, getParameter, hasParameter } from './utils/utils.js';
|
|
37
|
+
// @matter
|
|
38
|
+
import { DeviceTypeId, LogLevel as MatterLogLevel, LogFormat as MatterLogFormat, VendorId, EndpointServer } from '@matter/main';
|
|
39
|
+
import { ServerNode, Endpoint as EndpointNode, Environment, StorageService } from '@matter/main';
|
|
40
|
+
import { BasicInformationCluster } from '@matter/main/clusters';
|
|
41
|
+
import { FabricAction, MdnsService } from '@matter/main/protocol';
|
|
42
|
+
import { GenericSwitchDevice } from '@matter/main/devices';
|
|
43
|
+
import { AggregatorEndpoint } from '@matter/main/endpoints';
|
|
44
|
+
import { BridgedDeviceBasicInformationServer, SwitchServer } from '@matter/main/behaviors';
|
|
45
|
+
import { Device, logEndpoint } from '@project-chip/matter.js/device';
|
|
46
46
|
/**
|
|
47
47
|
* Represents the MatterbridgeEdge application.
|
|
48
48
|
*/
|
|
@@ -53,15 +53,16 @@ export class MatterbridgeEdge extends Matterbridge {
|
|
|
53
53
|
// Matter storage
|
|
54
54
|
matterStorageService;
|
|
55
55
|
// Mapping of CommissioningServer to ServerNode
|
|
56
|
-
|
|
56
|
+
csToServerNode = new Map();
|
|
57
57
|
// Mapping of Aggregator to AggregatorEndpoint
|
|
58
|
-
|
|
58
|
+
agToAggregatorEndpoint = new Map();
|
|
59
|
+
// Mapping of sessions
|
|
60
|
+
activeSessions = new Map();
|
|
59
61
|
constructor() {
|
|
60
62
|
super();
|
|
61
63
|
}
|
|
62
64
|
static async loadInstance(initialize = false) {
|
|
63
65
|
if (!MatterbridgeEdge.instance) {
|
|
64
|
-
// eslint-disable-next-line no-console
|
|
65
66
|
if (hasParameter('debug'))
|
|
66
67
|
console.log(GREEN + 'Creating a new instance of MatterbridgeEdge.', initialize ? 'Initializing...' : 'Not initializing...', rs);
|
|
67
68
|
MatterbridgeEdge.instance = new MatterbridgeEdge();
|
|
@@ -71,20 +72,23 @@ export class MatterbridgeEdge extends Matterbridge {
|
|
|
71
72
|
return MatterbridgeEdge.instance;
|
|
72
73
|
}
|
|
73
74
|
async initialize() {
|
|
74
|
-
// eslint-disable-next-line no-console
|
|
75
75
|
if (hasParameter('debug'))
|
|
76
76
|
console.log('Initializing MatterbridgeEdge...');
|
|
77
77
|
// Set the matterbridge directory
|
|
78
78
|
this.homeDirectory = getParameter('homedir') ?? os.homedir();
|
|
79
79
|
this.matterbridgeDirectory = path.join(this.homeDirectory, '.matterbridge');
|
|
80
|
+
this.matterStorageName = 'matterstorage' + (getParameter('profile') ? '.' + getParameter('profile') : '');
|
|
80
81
|
// Setup matter environment
|
|
81
|
-
this.environment.vars.set('log.level',
|
|
82
|
-
this.environment.vars.set('log.format',
|
|
83
|
-
this.environment.vars.set('path.root', path.join(this.matterbridgeDirectory,
|
|
82
|
+
this.environment.vars.set('log.level', MatterLogLevel.INFO);
|
|
83
|
+
this.environment.vars.set('log.format', MatterLogFormat.ANSI);
|
|
84
|
+
this.environment.vars.set('path.root', path.join(this.matterbridgeDirectory, this.matterStorageName));
|
|
84
85
|
this.environment.vars.set('runtime.signals', false);
|
|
85
86
|
this.environment.vars.set('runtime.exitcode', false);
|
|
86
87
|
// Initialize the base Matterbridge class
|
|
87
88
|
await super.initialize();
|
|
89
|
+
// Setup Matter mdnsInterface
|
|
90
|
+
if (this.mdnsInterface)
|
|
91
|
+
this.environment.vars.set('mdns.networkInterface', this.mdnsInterface);
|
|
88
92
|
// Setup Matter commissioning server
|
|
89
93
|
this.port = 5540;
|
|
90
94
|
this.passcode = 20242025;
|
|
@@ -96,12 +100,16 @@ export class MatterbridgeEdge extends Matterbridge {
|
|
|
96
100
|
this.matterStorageService = this.environment.get(StorageService);
|
|
97
101
|
this.log.info(`Matter node storage service created: ${this.matterStorageService.location}`);
|
|
98
102
|
this.storageManager = await this.matterStorageService.open('Matterbridge');
|
|
99
|
-
this.matterbridgeContext = this.storageManager.createContext('persist');
|
|
100
103
|
this.log.info('Matter node storage manager "Matterbridge" created');
|
|
104
|
+
this.matterbridgeContext = await this.createServerNodeContext('Matterbridge', 'Matterbridge', bridge.code, this.aggregatorVendorId, 'Matterbridge', this.aggregatorProductId, 'Matterbridge aggregator');
|
|
101
105
|
this.log.info('Matter node storage started');
|
|
106
|
+
// Backup matter storage since it is created/opened correctly
|
|
107
|
+
await this.backupMatterStorage(path.join(this.matterbridgeDirectory, this.matterStorageName), path.join(this.matterbridgeDirectory, this.matterStorageName + '.backup'));
|
|
102
108
|
}
|
|
103
109
|
async backupMatterStorage(storageName, backupName) {
|
|
104
|
-
|
|
110
|
+
this.log.info('Creating matter node storage backup...');
|
|
111
|
+
await copyDirectory(storageName, backupName);
|
|
112
|
+
this.log.info('Created matter node storage backup');
|
|
105
113
|
}
|
|
106
114
|
async stopMatterStorage() {
|
|
107
115
|
this.log.info('Closing matter node storage...');
|
|
@@ -129,18 +137,24 @@ export class MatterbridgeEdge extends Matterbridge {
|
|
|
129
137
|
async stopMatterServer() {
|
|
130
138
|
this.log.info(`Stopping matter server nodes in ${this.bridgeMode} mode...`);
|
|
131
139
|
if (this.bridgeMode === 'bridge') {
|
|
132
|
-
const serverNode = this.
|
|
133
|
-
if (serverNode)
|
|
140
|
+
const serverNode = this.csToServerNode.get('Matterbridge')?.serverNode;
|
|
141
|
+
if (serverNode) {
|
|
134
142
|
await this.stopServerNode(serverNode);
|
|
143
|
+
this.log.info(`Stopped matter server node Matterbridge`);
|
|
144
|
+
}
|
|
135
145
|
}
|
|
136
146
|
if (this.bridgeMode === 'childbridge') {
|
|
137
147
|
this.plugins.forEach(async (plugin) => {
|
|
138
|
-
const serverNode = this.
|
|
139
|
-
if (serverNode)
|
|
148
|
+
const serverNode = this.csToServerNode.get(plugin.name)?.serverNode;
|
|
149
|
+
if (serverNode) {
|
|
140
150
|
await this.stopServerNode(serverNode);
|
|
151
|
+
this.log.info(`Stopped matter server node ${plugin.name}`);
|
|
152
|
+
}
|
|
141
153
|
});
|
|
142
154
|
}
|
|
143
155
|
this.log.info('Stopped matter server nodes');
|
|
156
|
+
await this.environment.get(MdnsService)[Symbol.asyncDispose]();
|
|
157
|
+
this.log.info('Stopped MdnsService');
|
|
144
158
|
}
|
|
145
159
|
/**
|
|
146
160
|
* Creates a server node storage context.
|
|
@@ -163,10 +177,10 @@ export class MatterbridgeEdge extends Matterbridge {
|
|
|
163
177
|
async createServerNodeContext(pluginName, deviceName, deviceType, vendorId, vendorName, productId, productName, serialNumber) {
|
|
164
178
|
if (!this.matterStorageService)
|
|
165
179
|
throw new Error('No storage service initialized');
|
|
166
|
-
this.log.
|
|
180
|
+
this.log.info(`Creating server node storage context "${pluginName}.persist" for ${pluginName}...`);
|
|
167
181
|
const storageManager = await this.matterStorageService.open(pluginName);
|
|
168
182
|
const storageContext = storageManager.createContext('persist');
|
|
169
|
-
const random =
|
|
183
|
+
const random = randomBytes(8).toString('hex');
|
|
170
184
|
await storageContext.set('storeId', pluginName);
|
|
171
185
|
await storageContext.set('deviceName', deviceName);
|
|
172
186
|
await storageContext.set('deviceType', deviceType);
|
|
@@ -177,22 +191,28 @@ export class MatterbridgeEdge extends Matterbridge {
|
|
|
177
191
|
await storageContext.set('nodeLabel', productName.slice(0, 32));
|
|
178
192
|
await storageContext.set('productLabel', productName.slice(0, 32));
|
|
179
193
|
await storageContext.set('serialNumber', await storageContext.get('serialNumber', serialNumber ? serialNumber.slice(0, 32) : 'SN' + random));
|
|
180
|
-
await storageContext.set('uniqueId', await storageContext.get('uniqueId', random));
|
|
194
|
+
await storageContext.set('uniqueId', await storageContext.get('uniqueId', 'UI' + random));
|
|
181
195
|
await storageContext.set('softwareVersion', this.matterbridgeVersion !== '' && this.matterbridgeVersion.includes('.') ? parseInt(this.matterbridgeVersion.split('.')[0], 10) : 1);
|
|
182
196
|
await storageContext.set('softwareVersionString', this.matterbridgeVersion !== '' ? this.matterbridgeVersion : '1.0.0');
|
|
183
197
|
await storageContext.set('hardwareVersion', this.systemInformation.osRelease !== '' && this.systemInformation.osRelease.includes('.') ? parseInt(this.systemInformation.osRelease.split('.')[0], 10) : 1);
|
|
184
198
|
await storageContext.set('hardwareVersionString', this.systemInformation.osRelease !== '' ? this.systemInformation.osRelease : '1.0.0');
|
|
185
199
|
this.log.debug(`Created server node storage context "${pluginName}.persist" for ${pluginName}:`);
|
|
186
|
-
this.log.debug(`-
|
|
187
|
-
this.log.debug(`-
|
|
200
|
+
this.log.debug(`- storeId: ${await storageContext.get('storeId')}`);
|
|
201
|
+
this.log.debug(`- deviceName: ${await storageContext.get('deviceName')}`);
|
|
202
|
+
this.log.debug(`- deviceType: ${await storageContext.get('deviceType')}(0x${(await storageContext.get('deviceType'))?.toString(16).padStart(4, '0')})`);
|
|
203
|
+
this.log.debug(`- serialNumber: ${await storageContext.get('serialNumber')}`);
|
|
204
|
+
this.log.debug(`- uniqueId: ${await storageContext.get('uniqueId')}`);
|
|
188
205
|
this.log.debug(`- softwareVersion: ${await storageContext.get('softwareVersion')} softwareVersionString: ${await storageContext.get('softwareVersionString')}`);
|
|
189
206
|
this.log.debug(`- hardwareVersion: ${await storageContext.get('hardwareVersion')} hardwareVersionString: ${await storageContext.get('hardwareVersionString')}`);
|
|
190
207
|
return storageContext;
|
|
191
208
|
}
|
|
192
209
|
async createServerNode(storageContext, port = 5540, passcode = 20242025, discriminator = 3850) {
|
|
193
|
-
|
|
194
|
-
this.log.
|
|
195
|
-
this.log.debug(`-
|
|
210
|
+
const storeId = await storageContext.get('storeId');
|
|
211
|
+
this.log.info(`Creating server node for ${storeId}...`);
|
|
212
|
+
this.log.debug(`- deviceName: ${await storageContext.get('deviceName')}`);
|
|
213
|
+
this.log.debug(`- deviceType: ${await storageContext.get('deviceType')}(0x${(await storageContext.get('deviceType'))?.toString(16).padStart(4, '0')})`);
|
|
214
|
+
this.log.debug(`- serialNumber: ${await storageContext.get('serialNumber')}`);
|
|
215
|
+
this.log.debug(`- uniqueId: ${await storageContext.get('uniqueId')}`);
|
|
196
216
|
this.log.debug(`- softwareVersion: ${await storageContext.get('softwareVersion')} softwareVersionString: ${await storageContext.get('softwareVersionString')}`);
|
|
197
217
|
this.log.debug(`- hardwareVersion: ${await storageContext.get('hardwareVersion')} hardwareVersionString: ${await storageContext.get('hardwareVersionString')}`);
|
|
198
218
|
/**
|
|
@@ -200,7 +220,7 @@ export class MatterbridgeEdge extends Matterbridge {
|
|
|
200
220
|
*/
|
|
201
221
|
const serverNode = await ServerNode.create({
|
|
202
222
|
// Required: Give the Node a unique ID which is used to store the state of this node
|
|
203
|
-
id:
|
|
223
|
+
id: storeId,
|
|
204
224
|
// Provide Network relevant configuration like the port
|
|
205
225
|
// Optional when operating only one device on a host, Default port is 5540
|
|
206
226
|
network: {
|
|
@@ -237,17 +257,57 @@ export class MatterbridgeEdge extends Matterbridge {
|
|
|
237
257
|
hardwareVersionString: await storageContext.get('hardwareVersionString'),
|
|
238
258
|
},
|
|
239
259
|
});
|
|
260
|
+
const sanitizeFabrics = (fabrics) => {
|
|
261
|
+
// New type of fabric information: Record<FabricIndex, ExposedFabricInformation>
|
|
262
|
+
const sanitizedFabrics = this.sanitizeFabricInformations(Array.from(Object.values(serverNode.state.commissioning.fabrics)));
|
|
263
|
+
this.log.info(`Fabrics: ${debugStringify(sanitizedFabrics)}`);
|
|
264
|
+
if (this.bridgeMode === 'bridge') {
|
|
265
|
+
this.matterbridgeFabricInformations = sanitizedFabrics;
|
|
266
|
+
this.matterbridgeSessionInformations = [];
|
|
267
|
+
this.matterbridgePaired = true;
|
|
268
|
+
}
|
|
269
|
+
};
|
|
240
270
|
/**
|
|
241
271
|
* This event is triggered when the device is initially commissioned successfully.
|
|
242
272
|
* This means: It is added to the first fabric.
|
|
243
273
|
*/
|
|
244
|
-
serverNode.lifecycle.commissioned.on(() => this.log.notice(
|
|
274
|
+
serverNode.lifecycle.commissioned.on(() => this.log.notice(`Server node for ${storeId} was initially commissioned successfully!`));
|
|
245
275
|
/** This event is triggered when all fabrics are removed from the device, usually it also does a factory reset then. */
|
|
246
|
-
serverNode.lifecycle.decommissioned.on(() => this.log.notice(
|
|
276
|
+
serverNode.lifecycle.decommissioned.on(() => this.log.notice(`Server node for ${storeId} was fully decommissioned successfully!`));
|
|
247
277
|
/** This event is triggered when the device went online. This means that it is discoverable in the network. */
|
|
248
|
-
serverNode.lifecycle.online.on(() =>
|
|
278
|
+
serverNode.lifecycle.online.on(() => {
|
|
279
|
+
this.log.notice(`Server node for ${storeId} is online`);
|
|
280
|
+
if (!serverNode.lifecycle.isCommissioned) {
|
|
281
|
+
this.log.notice(`Server node for ${storeId} is not commissioned. Pair to commission ...`);
|
|
282
|
+
const { qrPairingCode, manualPairingCode } = serverNode.state.commissioning.pairingCodes;
|
|
283
|
+
if (this.bridgeMode === 'bridge') {
|
|
284
|
+
this.matterbridgeQrPairingCode = qrPairingCode;
|
|
285
|
+
this.matterbridgeManualPairingCode = manualPairingCode;
|
|
286
|
+
this.matterbridgeFabricInformations = [];
|
|
287
|
+
this.matterbridgeSessionInformations = [];
|
|
288
|
+
this.matterbridgePaired = false;
|
|
289
|
+
this.matterbridgeConnected = false;
|
|
290
|
+
this.log.notice(`QR Code URL: https://project-chip.github.io/connectedhomeip/qrcode.html?data=${qrPairingCode}`);
|
|
291
|
+
this.log.notice(`Manual pairing code: ${manualPairingCode}`);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
else {
|
|
295
|
+
this.log.notice(`Server node for ${storeId} is already commissioned. Waiting for controllers to connect ...`);
|
|
296
|
+
sanitizeFabrics(serverNode.state.commissioning.fabrics);
|
|
297
|
+
}
|
|
298
|
+
});
|
|
249
299
|
/** This event is triggered when the device went offline. it is not longer discoverable or connectable in the network. */
|
|
250
|
-
serverNode.lifecycle.offline.on(() =>
|
|
300
|
+
serverNode.lifecycle.offline.on(() => {
|
|
301
|
+
this.log.notice(`Server node for ${storeId} is offline`);
|
|
302
|
+
if (this.bridgeMode === 'bridge') {
|
|
303
|
+
this.matterbridgeQrPairingCode = undefined;
|
|
304
|
+
this.matterbridgeManualPairingCode = undefined;
|
|
305
|
+
this.matterbridgeFabricInformations = [];
|
|
306
|
+
this.matterbridgeSessionInformations = [];
|
|
307
|
+
this.matterbridgePaired = false;
|
|
308
|
+
this.matterbridgeConnected = false;
|
|
309
|
+
}
|
|
310
|
+
});
|
|
251
311
|
/**
|
|
252
312
|
* This event is triggered when a fabric is added, removed or updated on the device. Use this if more granular
|
|
253
313
|
* information is needed.
|
|
@@ -265,44 +325,42 @@ export class MatterbridgeEdge extends Matterbridge {
|
|
|
265
325
|
action = 'updated';
|
|
266
326
|
break;
|
|
267
327
|
}
|
|
268
|
-
this.log.notice(`Commissioned fabric index ${fabricIndex} ${action}
|
|
328
|
+
this.log.notice(`Commissioned fabric index ${fabricIndex} ${action} on server node for ${storeId}: ${debugStringify(serverNode.state.commissioning.fabrics[fabricIndex])}`);
|
|
329
|
+
sanitizeFabrics(serverNode.state.commissioning.fabrics);
|
|
269
330
|
});
|
|
331
|
+
const sanitizeSessions = (sessions) => {
|
|
332
|
+
const sanitizedSessions = this.sanitizeSessionInformation(sessions.map((session) => ({
|
|
333
|
+
...session,
|
|
334
|
+
secure: session.name.startsWith('secure'),
|
|
335
|
+
})));
|
|
336
|
+
this.log.debug(`Sessions: ${debugStringify(sanitizedSessions)}`);
|
|
337
|
+
if (this.bridgeMode === 'bridge') {
|
|
338
|
+
this.matterbridgeSessionInformations = sanitizedSessions;
|
|
339
|
+
}
|
|
340
|
+
};
|
|
270
341
|
/**
|
|
271
342
|
* This event is triggered when an operative new session was opened by a Controller.
|
|
272
343
|
* It is not triggered for the initial commissioning process, just afterwards for real connections.
|
|
273
344
|
*/
|
|
274
|
-
serverNode.events.sessions.opened.on((session) =>
|
|
345
|
+
serverNode.events.sessions.opened.on((session) => {
|
|
346
|
+
this.log.notice(`Session opened on server node for ${storeId}: ${debugStringify(session)}`);
|
|
347
|
+
sanitizeSessions(Object.values(serverNode.state.sessions.sessions));
|
|
348
|
+
});
|
|
275
349
|
/**
|
|
276
350
|
* This event is triggered when an operative session is closed by a Controller or because the Device goes offline.
|
|
277
351
|
*/
|
|
278
|
-
serverNode.events.sessions.closed.on((session) =>
|
|
352
|
+
serverNode.events.sessions.closed.on((session) => {
|
|
353
|
+
this.log.notice(`Session closed on server node for ${storeId}: ${debugStringify(session)}`);
|
|
354
|
+
sanitizeSessions(Object.values(serverNode.state.sessions.sessions));
|
|
355
|
+
});
|
|
279
356
|
/** This event is triggered when a subscription gets added or removed on an operative session. */
|
|
280
357
|
serverNode.events.sessions.subscriptionsChanged.on((session) => {
|
|
281
|
-
this.log.notice(
|
|
282
|
-
|
|
358
|
+
this.log.notice(`Session subscriptions changed on server node for ${storeId}: ${debugStringify(session)}`);
|
|
359
|
+
sanitizeSessions(Object.values(serverNode.state.sessions.sessions));
|
|
283
360
|
});
|
|
361
|
+
this.log.info(`Created server node for ${storeId}`);
|
|
284
362
|
return serverNode;
|
|
285
363
|
}
|
|
286
|
-
async showServerNodeQR(matterServerNode, storageContext) {
|
|
287
|
-
if (!matterServerNode || !storageContext)
|
|
288
|
-
return;
|
|
289
|
-
const node = await storageContext.get('storeId');
|
|
290
|
-
if (!matterServerNode.lifecycle.isCommissioned) {
|
|
291
|
-
this.log.notice(`${node} is not commissioned. Pair to commission ...`);
|
|
292
|
-
const { qrPairingCode, manualPairingCode } = matterServerNode.state.commissioning.pairingCodes;
|
|
293
|
-
// console.log(QrCode.get(qrPairingCode));
|
|
294
|
-
this.log.notice(`QR Code URL: https://project-chip.github.io/connectedhomeip/qrcode.html?data=${qrPairingCode}`);
|
|
295
|
-
this.log.notice(`Manual pairing code: ${manualPairingCode}`);
|
|
296
|
-
}
|
|
297
|
-
else {
|
|
298
|
-
this.log.notice(`${node} is already commissioned. Waiting for controllers to connect ...`);
|
|
299
|
-
this.log.notice('Fabrics:', matterServerNode.state.commissioning.fabrics);
|
|
300
|
-
for (const key in matterServerNode.state.commissioning.fabrics) {
|
|
301
|
-
const fabric = matterServerNode.state.commissioning.fabrics[FabricIndex(Number(key))];
|
|
302
|
-
this.log.notice(`- index ${fabric.fabricIndex} id ${fabric.fabricId} nodeId ${fabric.nodeId} rootVendor ${fabric.rootVendorId} rootNodeId ${fabric.rootNodeId}`);
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
364
|
async startServerNode(matterServerNode) {
|
|
307
365
|
if (!matterServerNode)
|
|
308
366
|
return;
|
|
@@ -312,60 +370,102 @@ export class MatterbridgeEdge extends Matterbridge {
|
|
|
312
370
|
async stopServerNode(matterServerNode) {
|
|
313
371
|
if (!matterServerNode)
|
|
314
372
|
return;
|
|
315
|
-
this.log.notice(`
|
|
373
|
+
this.log.notice(`Closing ${matterServerNode.id} server node`);
|
|
316
374
|
await matterServerNode.close();
|
|
317
375
|
}
|
|
318
376
|
async createAggregatorNode(storageContext) {
|
|
319
377
|
this.log.notice(`Creating ${await storageContext.get('storeId')} aggregator `);
|
|
320
|
-
const aggregator = new
|
|
378
|
+
const aggregator = new EndpointNode(AggregatorEndpoint, { id: `${await storageContext.get('storeId')}` });
|
|
321
379
|
return aggregator;
|
|
322
380
|
}
|
|
381
|
+
async addBridgedEndpoint(pluginName, device) {
|
|
382
|
+
// Check if the plugin is registered
|
|
383
|
+
const plugin = this.plugins.get(pluginName);
|
|
384
|
+
if (!plugin) {
|
|
385
|
+
this.log.error(`Error adding bridged device ${dev}${device.deviceName}${er} (${zb}${device.id}${er}) plugin ${plg}${pluginName}${er} not found`);
|
|
386
|
+
return;
|
|
387
|
+
}
|
|
388
|
+
// Register and add the device to the matterbridge aggregator node
|
|
389
|
+
if (this.bridgeMode === 'bridge') {
|
|
390
|
+
this.log.info(`Adding ${pluginName}:${device.deviceName} to Matterbridge aggregator node`);
|
|
391
|
+
const aggregatorNode = this.agToAggregatorEndpoint.get('Matterbridge')?.aggregatorNode;
|
|
392
|
+
await aggregatorNode?.add(device);
|
|
393
|
+
}
|
|
394
|
+
else if (this.bridgeMode === 'childbridge') {
|
|
395
|
+
if (plugin.type === 'DynamicPlatform') {
|
|
396
|
+
this.log.info(`Adding ${pluginName}:${device.deviceName} to ${pluginName} aggregator node`);
|
|
397
|
+
const aggregatorNode = this.agToAggregatorEndpoint.get(pluginName)?.aggregatorNode;
|
|
398
|
+
await aggregatorNode?.add(device);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
// TODO: Implement plugins and devices
|
|
402
|
+
if (plugin.registeredDevices !== undefined)
|
|
403
|
+
plugin.registeredDevices++;
|
|
404
|
+
if (plugin.addedDevices !== undefined)
|
|
405
|
+
plugin.addedDevices++;
|
|
406
|
+
// Add the device to the DeviceManager
|
|
407
|
+
this.devices.set(device);
|
|
408
|
+
this.log.info(`Added and registered bridged device (${plugin.registeredDevices}/${plugin.addedDevices}) ${dev}${device.deviceName}${nf} (${dev}${device.id}${nf}) for plugin ${plg}${pluginName}${nf}`);
|
|
409
|
+
}
|
|
410
|
+
async removeBridgedEndpoint(pluginName, device) {
|
|
411
|
+
// TODO: Implement removeBridgedEndpoint
|
|
412
|
+
}
|
|
413
|
+
async removeAllBridgedEndpoints(pluginName) {
|
|
414
|
+
// TODO: Implement removeAllBridgedEndpoints
|
|
415
|
+
}
|
|
323
416
|
async createCommissioningServerContext(pluginName, deviceName, deviceType, vendorId, vendorName, productId, productName) {
|
|
324
417
|
if (hasParameter('debug'))
|
|
325
|
-
this.log.warn(`createCommissioningServerContext
|
|
418
|
+
this.log.warn(`createCommissioningServerContext() for ${pluginName} => createServerNodeContext()`);
|
|
326
419
|
const storageContext = this.createServerNodeContext(pluginName, deviceName, deviceType, vendorId, vendorName, productId, productName);
|
|
327
420
|
return storageContext;
|
|
328
421
|
}
|
|
329
422
|
async importCommissioningServerContext(pluginName, device) {
|
|
330
423
|
if (hasParameter('debug'))
|
|
331
|
-
this.log.warn(`importCommissioningServerContext
|
|
424
|
+
this.log.warn(`importCommissioningServerContext() for ${pluginName} => createServerNodeContext()`);
|
|
332
425
|
const basic = device.getClusterServer(BasicInformationCluster);
|
|
333
426
|
if (!basic)
|
|
334
427
|
throw new Error('BasicInformationCluster not found');
|
|
335
428
|
const storageContext = this.createServerNodeContext(pluginName, basic.getNodeLabelAttribute(), DeviceTypeId(device.deviceType), basic.getVendorIdAttribute(), basic.getVendorNameAttribute(), basic.getProductIdAttribute(), basic.getProductNameAttribute(), basic.attributes.serialNumber?.getLocal());
|
|
336
429
|
return storageContext;
|
|
337
430
|
}
|
|
431
|
+
test = false;
|
|
338
432
|
async createCommisioningServer(context, pluginName) {
|
|
339
433
|
if (hasParameter('debug'))
|
|
340
|
-
this.log.warn(`createCommisioningServer
|
|
434
|
+
this.log.warn(`createCommisioningServer() for ${pluginName} => createServerNode()`);
|
|
341
435
|
const port = this.port;
|
|
342
436
|
const serverNode = await this.createServerNode(context, this.port++, this.passcode ? this.passcode++ : 20242025, this.discriminator ? this.discriminator++ : 3840);
|
|
343
437
|
const commissioningServer = {
|
|
344
438
|
getPort: () => port,
|
|
345
|
-
addDevice: (device) => {
|
|
439
|
+
addDevice: async (device) => {
|
|
440
|
+
// if (hasParameter('debug')) this.log.warn('CommissioningServer.addDevice()', device.name);
|
|
346
441
|
if (device instanceof Device) {
|
|
347
442
|
if (hasParameter('debug'))
|
|
348
443
|
this.log.warn('CommissioningServer.addDevice() => Device');
|
|
349
444
|
}
|
|
350
|
-
else if (device
|
|
445
|
+
else if (device.name === 'MA-aggregator') {
|
|
351
446
|
if (hasParameter('debug'))
|
|
352
447
|
this.log.warn('CommissioningServer.addDevice() => Aggregator');
|
|
353
|
-
const serverNode = this.
|
|
354
|
-
const aggregatorNode = this.
|
|
448
|
+
const serverNode = this.csToServerNode.get(pluginName)?.serverNode;
|
|
449
|
+
const aggregatorNode = this.agToAggregatorEndpoint.get(pluginName)?.aggregatorNode;
|
|
355
450
|
if (!serverNode || !aggregatorNode)
|
|
356
451
|
return;
|
|
357
|
-
serverNode.add(aggregatorNode);
|
|
452
|
+
await serverNode.add(aggregatorNode);
|
|
453
|
+
if (!this.test) {
|
|
454
|
+
this.test = true;
|
|
455
|
+
// await this.testEndpoints();
|
|
456
|
+
}
|
|
358
457
|
}
|
|
359
458
|
},
|
|
360
459
|
};
|
|
361
|
-
this.
|
|
460
|
+
this.csToServerNode.set(pluginName, { commissioningServer, serverNode });
|
|
362
461
|
return commissioningServer;
|
|
363
462
|
}
|
|
364
463
|
async createMatterAggregator(context, pluginName) {
|
|
365
464
|
if (hasParameter('debug'))
|
|
366
|
-
this.log.warn(`createMatterAggregator
|
|
465
|
+
this.log.warn(`createMatterAggregator() for ${pluginName} => createAggregatorNode()`);
|
|
367
466
|
const aggregatorNode = await this.createAggregatorNode(context);
|
|
368
467
|
const aggregator = {
|
|
468
|
+
name: 'MA-aggregator',
|
|
369
469
|
addBridgedDevice: (device) => {
|
|
370
470
|
if (hasParameter('debug'))
|
|
371
471
|
this.log.warn('Aggregator.addBridgedDevice() => not inplemented');
|
|
@@ -375,13 +475,13 @@ export class MatterbridgeEdge extends Matterbridge {
|
|
|
375
475
|
this.log.warn('Aggregator.removeBridgedDevice() => not inplemented');
|
|
376
476
|
},
|
|
377
477
|
};
|
|
378
|
-
this.
|
|
478
|
+
this.agToAggregatorEndpoint.set(pluginName, { aggregator, aggregatorNode });
|
|
379
479
|
return aggregator;
|
|
380
480
|
}
|
|
381
481
|
async showCommissioningQRCode(commissioningServer, storageContext, nodeContext, pluginName) {
|
|
382
482
|
if (hasParameter('debug'))
|
|
383
|
-
this.log.warn(`showCommissioningQRCode
|
|
384
|
-
const serverNode = this.
|
|
483
|
+
this.log.warn(`showCommissioningQRCode() for ${pluginName} => startServerNode()`);
|
|
484
|
+
const serverNode = this.csToServerNode.get(pluginName)?.serverNode;
|
|
385
485
|
if (!commissioningServer || !storageContext || !serverNode)
|
|
386
486
|
return;
|
|
387
487
|
await this.startServerNode(serverNode);
|
|
@@ -400,27 +500,330 @@ export class MatterbridgeEdge extends Matterbridge {
|
|
|
400
500
|
}
|
|
401
501
|
async startController() {
|
|
402
502
|
if (hasParameter('debug'))
|
|
403
|
-
this.log.warn(`
|
|
503
|
+
this.log.warn(`startController() => do nothing`);
|
|
504
|
+
}
|
|
505
|
+
async testEndpoints() {
|
|
506
|
+
const max = 10;
|
|
507
|
+
if (!this.matterbridgeContext)
|
|
508
|
+
return;
|
|
509
|
+
const aggregatorNode = this.agToAggregatorEndpoint.get('Matterbridge')?.aggregatorNode;
|
|
510
|
+
if (!aggregatorNode)
|
|
511
|
+
return;
|
|
512
|
+
/*
|
|
513
|
+
this.log.notice(`Creating OnOffLight1`);
|
|
514
|
+
const lightEndpoint = new MatterbridgeEndpoint(onOffLight, { uniqueStorageKey: 'OnOffLight1' }, true);
|
|
515
|
+
lightEndpoint.addDeviceType(bridgedNode);
|
|
516
|
+
lightEndpoint.createDefaultBridgedDeviceBasicInformationClusterServer('OnOffLight 1', '123456789', 0xfff1, 'Matterbridge', 'Light');
|
|
517
|
+
lightEndpoint.addDeviceType(powerSource);
|
|
518
|
+
lightEndpoint.createDefaultPowerSourceWiredClusterServer();
|
|
519
|
+
lightEndpoint.addDeviceType(electricalSensor);
|
|
520
|
+
lightEndpoint.addClusterServer(lightEndpoint.getDefaultElectricalEnergyMeasurementClusterServer());
|
|
521
|
+
lightEndpoint.addClusterServer(lightEndpoint.getDefaultElectricalPowerMeasurementClusterServer());
|
|
522
|
+
lightEndpoint.addRequiredClusterServers(lightEndpoint);
|
|
523
|
+
this.log.notice(`Adding OnOffLight1 to ${await this.matterbridgeContext.get<string>('storeId')} aggregator`);
|
|
524
|
+
await aggregatorNode.add(lightEndpoint);
|
|
525
|
+
logEndpoint(EndpointServer.forEndpoint(lightEndpoint));
|
|
526
|
+
|
|
527
|
+
this.log.notice(`Creating Outlet1`);
|
|
528
|
+
const outletEndpoint = new MatterbridgeEndpoint(onOffOutlet, { uniqueStorageKey: 'OnOffOutlet1' }, true);
|
|
529
|
+
outletEndpoint.addDeviceType(bridgedNode);
|
|
530
|
+
outletEndpoint.createDefaultBridgedDeviceBasicInformationClusterServer('OnOffOutlet 1', '123456789', 0xfff1, 'Matterbridge', 'Outlet');
|
|
531
|
+
outletEndpoint.addDeviceType(powerSource);
|
|
532
|
+
outletEndpoint.createDefaultPowerSourceReplaceableBatteryClusterServer();
|
|
533
|
+
outletEndpoint.addDeviceType(electricalSensor);
|
|
534
|
+
outletEndpoint.addClusterServer(outletEndpoint.getDefaultElectricalEnergyMeasurementClusterServer());
|
|
535
|
+
outletEndpoint.addClusterServer(outletEndpoint.getDefaultElectricalPowerMeasurementClusterServer());
|
|
536
|
+
outletEndpoint.addRequiredClusterServers(outletEndpoint);
|
|
537
|
+
const input0 = outletEndpoint.addChildDeviceTypeWithClusterServer('Input:0', [genericSwitch], undefined, undefined, true);
|
|
538
|
+
const input1 = outletEndpoint.addChildDeviceTypeWithClusterServer('Input:1', [genericSwitch], undefined, undefined, true);
|
|
539
|
+
this.log.notice(`Adding OnOffOutlet1 to ${await this.matterbridgeContext.get<string>('storeId')} aggregator`);
|
|
540
|
+
await aggregatorNode.add(outletEndpoint);
|
|
541
|
+
logEndpoint(EndpointServer.forEndpoint(outletEndpoint));
|
|
542
|
+
*/
|
|
543
|
+
this.log.notice(`Creating switchEnpoint2`);
|
|
544
|
+
const switchEnpoint2 = new EndpointNode(GenericSwitchDevice.with(BridgedDeviceBasicInformationServer, SwitchServer.with('MomentarySwitch', 'MomentarySwitchLongPress', 'MomentarySwitchMultiPress', 'MomentarySwitchRelease')), {
|
|
545
|
+
id: 'GenericSwitch',
|
|
546
|
+
bridgedDeviceBasicInformation: {
|
|
547
|
+
vendorId: VendorId(await this.matterbridgeContext.get('vendorId')),
|
|
548
|
+
vendorName: await this.matterbridgeContext.get('vendorName'),
|
|
549
|
+
productName: 'GenericSwitch',
|
|
550
|
+
productLabel: 'GenericSwitch',
|
|
551
|
+
nodeLabel: 'GenericSwitch',
|
|
552
|
+
serialNumber: 'SN 0x123456739',
|
|
553
|
+
uniqueId: '0x123456739',
|
|
554
|
+
reachable: true,
|
|
555
|
+
},
|
|
556
|
+
switch: {
|
|
557
|
+
numberOfPositions: 2,
|
|
558
|
+
currentPosition: 0,
|
|
559
|
+
multiPressMax: 2,
|
|
560
|
+
},
|
|
561
|
+
});
|
|
562
|
+
this.log.notice(`Adding switchEnpoint2 to ${await this.matterbridgeContext.get('storeId')} aggregator`);
|
|
563
|
+
await aggregatorNode.add(switchEnpoint2);
|
|
564
|
+
logEndpoint(EndpointServer.forEndpoint(switchEnpoint2));
|
|
565
|
+
if (switchEnpoint2.behaviors.has(SwitchServer))
|
|
566
|
+
this.log.notice(`SwitchServer found`);
|
|
567
|
+
switchEnpoint2.act((agent) => agent['switch'].events['initialPress'].emit({ newPosition: 1 }, agent.context));
|
|
568
|
+
const device = new MatterbridgeEndpoint(genericSwitch, { uniqueStorageKey: 'GenericSwitch 2' }, true);
|
|
569
|
+
device.createDefaultSwitchClusterServer();
|
|
570
|
+
device.addRequiredClusterServers(device);
|
|
571
|
+
await aggregatorNode.add(device);
|
|
572
|
+
logEndpoint(EndpointServer.forEndpoint(device));
|
|
573
|
+
await device.triggerSwitchEvent('Single', this.log);
|
|
574
|
+
await device.triggerSwitchEvent('Double', this.log);
|
|
575
|
+
await device.triggerSwitchEvent('Long', this.log);
|
|
576
|
+
const device1 = new MatterbridgeEndpoint(genericSwitch, { uniqueStorageKey: 'GenericSwitch 3' }, true);
|
|
577
|
+
device1.createDefaultLatchingSwitchClusterServer();
|
|
578
|
+
device1.addRequiredClusterServers(device1);
|
|
579
|
+
await aggregatorNode.add(device1);
|
|
580
|
+
logEndpoint(EndpointServer.forEndpoint(device1));
|
|
581
|
+
await device1.triggerSwitchEvent('Press', this.log);
|
|
582
|
+
await device1.triggerSwitchEvent('Release', this.log);
|
|
583
|
+
/*
|
|
584
|
+
this.log.notice(`Creating TestLight`);
|
|
585
|
+
const matterbridgeDevice = new MatterbridgeEndpoint(onOffLight, { uniqueStorageKey: 'Test .Light:2' }, true);
|
|
586
|
+
matterbridgeDevice.behaviors.require(MatterbridgeIdentifyServer, {
|
|
587
|
+
identifyTime: 0,
|
|
588
|
+
identifyType: Identify.IdentifyType.None,
|
|
589
|
+
});
|
|
590
|
+
matterbridgeDevice.behaviors.require(GroupsServer);
|
|
591
|
+
matterbridgeDevice.behaviors.require(MatterbridgeOnOffServer, {
|
|
592
|
+
onOff: false,
|
|
593
|
+
});
|
|
594
|
+
matterbridgeDevice.behaviors.require(MatterbridgeLevelControlServer, {
|
|
595
|
+
currentLevel: 0,
|
|
596
|
+
options: { executeIfOff: false },
|
|
597
|
+
});
|
|
598
|
+
matterbridgeDevice.behaviors.require(MatterbridgeColorControlServer.with(ColorControl.Feature.HueSaturation, ColorControl.Feature.Xy, ColorControl.Feature.ColorTemperature), {
|
|
599
|
+
colorCapabilities: { xy: true, hueSaturation: true, colorLoop: false, enhancedHue: false, colorTemperature: true },
|
|
600
|
+
colorMode: ColorControl.ColorMode.ColorTemperatureMireds,
|
|
601
|
+
enhancedColorMode: ColorControl.EnhancedColorMode.ColorTemperatureMireds,
|
|
602
|
+
options: { executeIfOff: false },
|
|
603
|
+
numberOfPrimaries: null,
|
|
604
|
+
currentX: 24939,
|
|
605
|
+
currentY: 24701,
|
|
606
|
+
currentHue: 0,
|
|
607
|
+
currentSaturation: 0,
|
|
608
|
+
colorTemperatureMireds: 450,
|
|
609
|
+
colorTempPhysicalMinMireds: 150,
|
|
610
|
+
colorTempPhysicalMaxMireds: 450,
|
|
611
|
+
coupleColorTempToLevelMinMireds: 150,
|
|
612
|
+
startUpColorTemperatureMireds: null,
|
|
613
|
+
});
|
|
614
|
+
matterbridgeDevice.behaviors.require(BridgedDeviceBasicInformationServer, {
|
|
615
|
+
vendorId: VendorId(await this.matterbridgeContext.get<number>('vendorId')),
|
|
616
|
+
vendorName: await this.matterbridgeContext.get<string>('vendorName'),
|
|
617
|
+
productName: 'TestLight2',
|
|
618
|
+
productLabel: 'TestLight2',
|
|
619
|
+
nodeLabel: 'TestLight2',
|
|
620
|
+
serialNumber: 'SN 0x123456789',
|
|
621
|
+
uniqueId: '0x123456789',
|
|
622
|
+
reachable: true,
|
|
623
|
+
});
|
|
624
|
+
|
|
625
|
+
// await matterbridgeDevice.setTagList(null, 0x07, 1, 'endpoint 2');
|
|
626
|
+
// await matterbridgeDevice.configureColorControlCluster(false, false, true, ColorControl.ColorMode.ColorTemperatureMireds);
|
|
627
|
+
|
|
628
|
+
this.log.notice(`Adding TestLight`);
|
|
629
|
+
await aggregatorNode?.add(matterbridgeDevice);
|
|
630
|
+
|
|
631
|
+
this.log.notice(`Creating switchEnpoint1`);
|
|
632
|
+
const switchEnpoint2 = new EndpointNode(
|
|
633
|
+
GenericSwitchDevice.with(DescriptorServer.with(Descriptor.Feature.TagList), BridgedDeviceBasicInformationServer, SwitchServer.with('MomentarySwitch', 'MomentarySwitchLongPress', 'MomentarySwitchMultiPress', 'MomentarySwitchRelease')),
|
|
634
|
+
{
|
|
635
|
+
id: 'GenericSwitch1',
|
|
636
|
+
descriptor: {
|
|
637
|
+
tagList: [{ mfgCode: null, namespaceId: 0x07, tag: 1, label: 'Switch1' }],
|
|
638
|
+
},
|
|
639
|
+
bridgedDeviceBasicInformation: {
|
|
640
|
+
vendorId: VendorId(await this.matterbridgeContext.get<number>('vendorId')),
|
|
641
|
+
vendorName: await this.matterbridgeContext.get<string>('vendorName'),
|
|
642
|
+
|
|
643
|
+
productName: 'GenericSwitch',
|
|
644
|
+
productLabel: 'GenericSwitch',
|
|
645
|
+
nodeLabel: 'GenericSwitch',
|
|
646
|
+
|
|
647
|
+
serialNumber: 'SN 0x1234567397',
|
|
648
|
+
uniqueId: '0x1234567397',
|
|
649
|
+
reachable: true,
|
|
650
|
+
},
|
|
651
|
+
switch: {
|
|
652
|
+
numberOfPositions: 2,
|
|
653
|
+
currentPosition: 0,
|
|
654
|
+
multiPressMax: 2,
|
|
655
|
+
},
|
|
656
|
+
},
|
|
657
|
+
);
|
|
658
|
+
this.log.notice(`Creating switchEnpoint2`);
|
|
659
|
+
await aggregatorNode?.add(switchEnpoint2);
|
|
660
|
+
*/
|
|
661
|
+
/*
|
|
662
|
+
const lightEndpoint1 = new EndpointNode(ColorTemperatureLightDevice.with(BridgedDeviceBasicInformationServer), {
|
|
663
|
+
// }, MatterbridgeIdentifyServer, MatterbridgeOnOffServer, MatterbridgeLevelControlServer, MatterbridgeColorControlServer), {
|
|
664
|
+
id: 'OnOffLight',
|
|
665
|
+
bridgedDeviceBasicInformation: {
|
|
666
|
+
vendorId: VendorId(await this.matterbridgeContext.get<number>('vendorId')),
|
|
667
|
+
vendorName: await this.matterbridgeContext.get<string>('vendorName'),
|
|
668
|
+
|
|
669
|
+
productName: 'Light',
|
|
670
|
+
productLabel: 'Light',
|
|
671
|
+
nodeLabel: 'Light',
|
|
672
|
+
|
|
673
|
+
serialNumber: 'SN 0x123456789',
|
|
674
|
+
uniqueId: '0x123456789',
|
|
675
|
+
reachable: true,
|
|
676
|
+
},
|
|
677
|
+
levelControl: {
|
|
678
|
+
currentLevel: 0,
|
|
679
|
+
options: { executeIfOff: false, coupleColorTempToLevel: false },
|
|
680
|
+
},
|
|
681
|
+
colorControl: {
|
|
682
|
+
colorTemperatureMireds: 450,
|
|
683
|
+
colorMode: ColorControl.ColorMode.ColorTemperatureMireds,
|
|
684
|
+
colorTempPhysicalMinMireds: 150,
|
|
685
|
+
colorTempPhysicalMaxMireds: 450,
|
|
686
|
+
coupleColorTempToLevelMinMireds: 150,
|
|
687
|
+
startUpColorTemperatureMireds: 450,
|
|
688
|
+
},
|
|
689
|
+
});
|
|
690
|
+
lightEndpoint1.behaviors.require(ColorControlServer.with('ColorTemperature'), {
|
|
691
|
+
colorTemperatureMireds: 450,
|
|
692
|
+
colorMode: ColorControl.ColorMode.ColorTemperatureMireds,
|
|
693
|
+
colorTempPhysicalMinMireds: 150,
|
|
694
|
+
colorTempPhysicalMaxMireds: 450,
|
|
695
|
+
coupleColorTempToLevelMinMireds: 150,
|
|
696
|
+
startUpColorTemperatureMireds: 450,
|
|
697
|
+
});
|
|
698
|
+
await aggregatorNode?.add(lightEndpoint1);
|
|
699
|
+
|
|
700
|
+
/*
|
|
701
|
+
lightEndpoint1.behaviors.require(MatterbridgeIdentifyServer);
|
|
702
|
+
lightEndpoint1.behaviors.require(MatterbridgeOnOffServer);
|
|
703
|
+
lightEndpoint1.behaviors.require(MatterbridgeLevelControlServer);
|
|
704
|
+
lightEndpoint1.behaviors.require(MatterbridgeColorControlServer, {
|
|
705
|
+
colorTemperatureMireds: 250,
|
|
706
|
+
colorMode: ColorControl.ColorMode.ColorTemperatureMireds,
|
|
707
|
+
colorTempPhysicalMinMireds: 150,
|
|
708
|
+
colorTempPhysicalMaxMireds: 450,
|
|
709
|
+
coupleColorTempToLevelMinMireds: 150,
|
|
710
|
+
startUpColorTemperatureMireds: 450,
|
|
711
|
+
});
|
|
712
|
+
await aggregatorNode?.add(lightEndpoint1);
|
|
713
|
+
|
|
714
|
+
this.log.notice(`Creating switchEnpoint2`);
|
|
715
|
+
const switchEnpoint2 = new EndpointNode(GenericSwitchDevice.with(BridgedDeviceBasicInformationServer, SwitchServer.with('MomentarySwitch', 'MomentarySwitchLongPress', 'MomentarySwitchMultiPress', 'MomentarySwitchRelease')), {
|
|
716
|
+
id: 'GenericSwitch',
|
|
717
|
+
bridgedDeviceBasicInformation: {
|
|
718
|
+
vendorId: VendorId(await this.matterbridgeContext.get<number>('vendorId')),
|
|
719
|
+
vendorName: await this.matterbridgeContext.get<string>('vendorName'),
|
|
720
|
+
|
|
721
|
+
productName: 'GenericSwitch',
|
|
722
|
+
productLabel: 'GenericSwitch',
|
|
723
|
+
nodeLabel: 'GenericSwitch',
|
|
724
|
+
|
|
725
|
+
serialNumber: 'SN 0x123456739',
|
|
726
|
+
uniqueId: '0x123456739',
|
|
727
|
+
reachable: true,
|
|
728
|
+
},
|
|
729
|
+
switch: {
|
|
730
|
+
numberOfPositions: 2,
|
|
731
|
+
currentPosition: 0,
|
|
732
|
+
multiPressMax: 2,
|
|
733
|
+
},
|
|
734
|
+
});
|
|
735
|
+
await aggregatorNode?.add(switchEnpoint2);
|
|
736
|
+
*/
|
|
737
|
+
/*
|
|
738
|
+
for (let i = 1; i <= max; i++) {
|
|
739
|
+
this.log.notice(`Creating lightEndpoint${i}`);
|
|
740
|
+
const lightEndpoint = new MatterbridgeEndpoint(onOffLight, { uniqueStorageKey: 'OnOffLight' + i });
|
|
741
|
+
lightEndpoint.addClusterServer(lightEndpoint.getDefaultBridgedDeviceBasicInformationClusterServer('OnOffLight' + i, '123456789', 0xfff1, 'Matterbridge', 'Light'));
|
|
742
|
+
this.log.notice(`Adding lightEndpoint${i} to ${await this.matterbridgeContext.get<string>('storeId')} aggregator`);
|
|
743
|
+
await aggregatorNode?.add(lightEndpoint);
|
|
744
|
+
setInterval(async () => {
|
|
745
|
+
const state = lightEndpoint.getAttribute(OnOffCluster.id, 'onOff');
|
|
746
|
+
lightEndpoint.setAttribute(OnOffCluster.id, 'onOff', !state);
|
|
747
|
+
this.log.notice(`Setting state for lightEndpoint${i} from:`, state, 'to:', !state);
|
|
748
|
+
}, 10000);
|
|
749
|
+
}
|
|
750
|
+
for (let i = 1; i <= max; i++) {
|
|
751
|
+
this.log.notice(`Creating outletEndpoint${i}`);
|
|
752
|
+
const lightEndpoint = new MatterbridgeEndpoint(onOffOutlet, { uniqueStorageKey: 'OnOffOutlet' + i });
|
|
753
|
+
lightEndpoint.addClusterServer(lightEndpoint.getDefaultBridgedDeviceBasicInformationClusterServer('OnOffOutlet' + i, '123456789', 0xfff1, 'Matterbridge', 'Outlet'));
|
|
754
|
+
this.log.notice(`Adding outletEndpoint${i} to ${await this.matterbridgeContext.get<string>('storeId')} aggregator`);
|
|
755
|
+
await aggregatorNode?.add(lightEndpoint);
|
|
756
|
+
setInterval(async () => {
|
|
757
|
+
const state = lightEndpoint.getAttribute(OnOffCluster.id, 'onOff');
|
|
758
|
+
lightEndpoint.setAttribute(OnOffCluster.id, 'onOff', !state);
|
|
759
|
+
this.log.notice(`Setting state for outletEndpoint${i} from:`, state, 'to:', !state);
|
|
760
|
+
}, 10000);
|
|
761
|
+
}
|
|
762
|
+
*/
|
|
404
763
|
}
|
|
405
764
|
}
|
|
765
|
+
/*
|
|
766
|
+
/*
|
|
767
|
+
matterbridgeDevice.behaviors.require(MatterbridgeColorControlServer.with(ColorControl.Feature.HueSaturation, ColorControl.Feature.Xy, ColorControl.Feature.ColorTemperature), {
|
|
768
|
+
colorCapabilities: { xy: true, hueSaturation: true, colorLoop: false, enhancedHue: false, colorTemperature: true },
|
|
769
|
+
colorMode: ColorControl.ColorMode.ColorTemperatureMireds,
|
|
770
|
+
enhancedColorMode: ColorControl.EnhancedColorMode.ColorTemperatureMireds,
|
|
771
|
+
options: { executeIfOff: false },
|
|
772
|
+
numberOfPrimaries: null,
|
|
773
|
+
currentX: 24939,
|
|
774
|
+
currentY: 24701,
|
|
775
|
+
currentHue: 0,
|
|
776
|
+
currentSaturation: 0,
|
|
777
|
+
colorTemperatureMireds: 450,
|
|
778
|
+
colorTempPhysicalMinMireds: 150,
|
|
779
|
+
colorTempPhysicalMaxMireds: 450,
|
|
780
|
+
coupleColorTempToLevelMinMireds: 150,
|
|
781
|
+
startUpColorTemperatureMireds: null,
|
|
782
|
+
});
|
|
783
|
+
matterbridgeDevice.behaviors.require(MatterbridgeColorControlServer.with(ColorControl.Feature.ColorTemperature), {
|
|
784
|
+
colorCapabilities: { xy: false, hueSaturation: false, colorLoop: false, enhancedHue: false, colorTemperature: true },
|
|
785
|
+
colorMode: ColorControl.ColorMode.ColorTemperatureMireds,
|
|
786
|
+
enhancedColorMode: ColorControl.EnhancedColorMode.ColorTemperatureMireds,
|
|
787
|
+
options: { executeIfOff: false },
|
|
788
|
+
numberOfPrimaries: null,
|
|
789
|
+
colorTemperatureMireds: 450,
|
|
790
|
+
colorTempPhysicalMinMireds: 150,
|
|
791
|
+
colorTempPhysicalMaxMireds: 450,
|
|
792
|
+
coupleColorTempToLevelMinMireds: 150,
|
|
793
|
+
startUpColorTemperatureMireds: null,
|
|
794
|
+
});
|
|
795
|
+
*/
|
|
796
|
+
/*
|
|
797
|
+
matterbridgeDevice.behaviors.require(MatterbridgeColorControlServer.with(ColorControl.Feature.HueSaturation, ColorControl.Feature.Xy), {
|
|
798
|
+
colorCapabilities: { xy: true, hueSaturation: true, colorLoop: false, enhancedHue: false, colorTemperature: false },
|
|
799
|
+
colorMode: ColorControl.ColorMode.CurrentHueAndCurrentSaturation,
|
|
800
|
+
enhancedColorMode: ColorControl.EnhancedColorMode.CurrentHueAndCurrentSaturation,
|
|
801
|
+
options: { executeIfOff: false },
|
|
802
|
+
numberOfPrimaries: null,
|
|
803
|
+
currentX: 24939,
|
|
804
|
+
currentY: 24701,
|
|
805
|
+
currentHue: 0,
|
|
806
|
+
currentSaturation: 0,
|
|
807
|
+
});
|
|
406
808
|
// node dist/matterbridgeEdge.js MatterbridgeEdge -debug -ssl -frontend 443
|
|
407
809
|
if (process.argv.includes('MatterbridgeEdge')) {
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
810
|
+
const matterbridge = await MatterbridgeEdge.loadInstance(true);
|
|
811
|
+
|
|
812
|
+
process.on('SIGINT', async function () {
|
|
813
|
+
// eslint-disable-next-line no-console
|
|
814
|
+
console.log('Caught interrupt signal');
|
|
815
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
816
|
+
if (matterbridge) await (matterbridge as any).cleanup('shutting down...', false);
|
|
817
|
+
// if (matterbridge && matterbridge.matterServerNode && matterbridge.matterServerNodeContext) await matterbridge.stopServerNode(matterbridge.matterServerNode, matterbridge.matterServerNodeContext);
|
|
818
|
+
const exit = setTimeout(() => {
|
|
819
|
+
// eslint-disable-next-line no-console
|
|
820
|
+
console.log('Exiting after caught interrupt signal');
|
|
821
|
+
process.exit();
|
|
822
|
+
}, 10000);
|
|
823
|
+
exit.unref();
|
|
824
|
+
});
|
|
423
825
|
}
|
|
826
|
+
*/
|
|
424
827
|
/*
|
|
425
828
|
async startBridgeNode(): Promise<void> {
|
|
426
829
|
this.log.notice(`Creating lightEndpoint1`);
|