@project-chip/matter-node.js-examples 0.5.0 → 0.5.1-alpha.0-20231005-d8f807e

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. package/README.md +7 -1
  2. package/dist/cjs/examples/BridgedDevicesNode.d.ts +8 -0
  3. package/dist/cjs/examples/BridgedDevicesNode.d.ts.map +1 -0
  4. package/dist/cjs/examples/BridgedDevicesNode.js +135 -0
  5. package/dist/cjs/examples/BridgedDevicesNode.js.map +7 -0
  6. package/dist/cjs/examples/ComposedDeviceNode.d.ts +8 -0
  7. package/dist/cjs/examples/ComposedDeviceNode.d.ts.map +1 -0
  8. package/dist/cjs/examples/ComposedDeviceNode.js +132 -0
  9. package/dist/cjs/examples/ComposedDeviceNode.js.map +7 -0
  10. package/dist/cjs/examples/ControllerNode.d.ts +8 -0
  11. package/dist/cjs/examples/ControllerNode.d.ts.map +1 -0
  12. package/dist/cjs/examples/ControllerNode.js +172 -0
  13. package/dist/cjs/examples/ControllerNode.js.map +7 -0
  14. package/dist/cjs/examples/DeviceNode.d.ts +8 -0
  15. package/dist/cjs/examples/DeviceNode.d.ts.map +1 -0
  16. package/dist/cjs/examples/DeviceNode.js +174 -0
  17. package/dist/cjs/examples/DeviceNode.js.map +7 -0
  18. package/dist/cjs/examples/MultiDeviceNode.d.ts +8 -0
  19. package/dist/cjs/examples/MultiDeviceNode.d.ts.map +1 -0
  20. package/dist/cjs/examples/MultiDeviceNode.js +140 -0
  21. package/dist/cjs/examples/MultiDeviceNode.js.map +7 -0
  22. package/dist/cjs/examples/cluster/DummyWifiNetworkCommissioningClusterServer.d.ts +18 -0
  23. package/dist/cjs/examples/cluster/DummyWifiNetworkCommissioningClusterServer.d.ts.map +1 -0
  24. package/dist/cjs/examples/cluster/DummyWifiNetworkCommissioningClusterServer.js +166 -0
  25. package/dist/cjs/examples/cluster/DummyWifiNetworkCommissioningClusterServer.js.map +7 -0
  26. package/dist/cjs/package.json +1 -0
  27. package/package.json +21 -25
  28. package/src/examples/BridgedDevicesNode.ts +247 -0
  29. package/src/examples/ComposedDeviceNode.ts +245 -0
  30. package/src/examples/ControllerNode.ts +294 -0
  31. package/src/examples/DeviceNode.ts +288 -0
  32. package/src/examples/MultiDeviceNode.ts +260 -0
  33. package/src/examples/cluster/DummyWifiNetworkCommissioningClusterServer.ts +181 -0
  34. package/dist/examples/BridgedDevicesNode.js +0 -218
  35. package/dist/examples/BridgedDevicesNode.js.map +0 -1
  36. package/dist/examples/ComposedDeviceNode.js +0 -217
  37. package/dist/examples/ComposedDeviceNode.js.map +0 -1
  38. package/dist/examples/ControllerNode.js +0 -261
  39. package/dist/examples/ControllerNode.js.map +0 -1
  40. package/dist/examples/DeviceNode.js +0 -358
  41. package/dist/examples/DeviceNode.js.map +0 -1
  42. package/dist/examples/MultiDeviceNode.js +0 -228
  43. package/dist/examples/MultiDeviceNode.js.map +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@project-chip/matter-node.js-examples",
3
- "version": "0.5.0",
3
+ "version": "0.5.1-alpha.0-20231005-d8f807e",
4
4
  "description": "CLI/Reference implementation scripts for Matter protocol for node.js",
5
5
  "keywords": [
6
6
  "iot",
@@ -24,35 +24,29 @@
24
24
  "url": "https://github.com/project-chip/matter.js.git"
25
25
  },
26
26
  "scripts": {
27
- "clean": "rm -rf dist && rm -f *.tsbuildinfo",
28
- "build": "tsc -b tsconfig.dist.json",
29
- "build-clean": "npm run clean && npm run build",
30
- "matter-device": "ts-node --project tsconfig.dist.json src/examples/DeviceNode.ts",
31
- "matter-bridge": "ts-node --project tsconfig.dist.json src/examples/BridgedDevicesNode.ts",
32
- "matter-composeddevice": "ts-node --project tsconfig.dist.json src/examples/ComposedDeviceNode.ts",
33
- "matter-multidevice": "ts-node --project tsconfig.dist.json src/examples/MultiDeviceNode.ts",
34
- "matter-controller": "ts-node --project tsconfig.dist.json src/examples/ControllerNode.ts",
35
- "test": "true"
27
+ "clean": "build clean",
28
+ "build": "build",
29
+ "build-clean": "build --clean",
30
+ "matter-device": "run src/examples/DeviceNode.ts",
31
+ "matter-bridge": "run src/examples/BridgedDevicesNode.ts",
32
+ "matter-composeddevice": "run src/examples/ComposedDeviceNode.ts",
33
+ "matter-multidevice": "run src/examples/MultiDeviceNode.ts",
34
+ "matter-controller": "run src/examples/ControllerNode.ts"
36
35
  },
37
36
  "bin": {
38
- "matter-device": "./dist/examples/DeviceNode.js",
39
- "matter-bridge": "./dist/examples/BridgedDevicesNode.js",
40
- "matter-composeddevice": "./dist/examples/ComposedDeviceNode.js",
41
- "matter-multidevice": "./dist/examples/MultiDeviceNode.js",
42
- "matter-controller": "./dist/examples/ControllerNode.js"
37
+ "matter-device": "./dist/cjs/examples/DeviceNode.js",
38
+ "matter-bridge": "./dist/cjs/examples/BridgedDevicesNode.js",
39
+ "matter-composeddevice": "./dist/cjs/examples/ComposedDeviceNode.js",
40
+ "matter-multidevice": "./dist/cjs/examples/MultiDeviceNode.js",
41
+ "matter-controller": "./dist/cjs/examples/ControllerNode.js"
43
42
  },
44
43
  "devDependencies": {
45
- "@typescript-eslint/eslint-plugin": "^5.62.0",
46
- "@typescript-eslint/parser": "^5.62.0",
47
- "eslint": "^8.47.0",
48
- "eslint-import-resolver-typescript": "^3.6.0",
49
- "eslint-plugin-import": "^2.28.1",
50
- "ts-node": "^10.9.1",
51
- "typescript": "^4.9.5"
44
+ "@project-chip/matter.js-tools": "0.5.1-alpha.0-20231005-d8f807e",
45
+ "typescript": "^5.2.2"
52
46
  },
53
47
  "dependencies": {
54
- "@project-chip/matter-node.js": "^0.5.0",
55
- "@project-chip/matter-node-ble.js": "^0.5.0"
48
+ "@project-chip/matter-node-ble.js": "0.5.1-alpha.0-20231005-d8f807e",
49
+ "@project-chip/matter-node.js": "0.5.1-alpha.0-20231005-d8f807e"
56
50
  },
57
51
  "engines": {
58
52
  "_comment": "For Crypto.hkdf support",
@@ -60,10 +54,12 @@
60
54
  },
61
55
  "files": [
62
56
  "dist/**/*",
57
+ "src/**/*",
63
58
  "LICENSE",
64
59
  "README.md"
65
60
  ],
66
61
  "publishConfig": {
67
62
  "access": "public"
68
- }
63
+ },
64
+ "gitHead": "2530bea61cf2164af25acde6b4115eefcc3221fd"
69
65
  }
@@ -0,0 +1,247 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * @license
4
+ * Copyright 2022 The node-matter Authors
5
+ * SPDX-License-Identifier: Apache-2.0
6
+ */
7
+
8
+ /**
9
+ * This example shows how to create a device bridge that exposed multiple devices.
10
+ * It can be used as CLI script and starting point for your own device node implementation.
11
+ */
12
+
13
+ /**
14
+ * Import needed modules from @project-chip/matter-node.js
15
+ */
16
+ // Include this first to auto-register Crypto, Network and Time Node.js implementations
17
+ import { CommissioningServer, MatterServer } from "@project-chip/matter-node.js";
18
+
19
+ import { Aggregator, DeviceTypes, OnOffLightDevice, OnOffPluginUnitDevice } from "@project-chip/matter-node.js/device";
20
+ import { Format, Level, Logger } from "@project-chip/matter-node.js/log";
21
+ import { StorageBackendDisk, StorageManager } from "@project-chip/matter-node.js/storage";
22
+ import { Time } from "@project-chip/matter-node.js/time";
23
+ import {
24
+ commandExecutor,
25
+ getIntParameter,
26
+ getParameter,
27
+ hasParameter,
28
+ requireMinNodeVersion,
29
+ } from "@project-chip/matter-node.js/util";
30
+ import { VendorId } from "@project-chip/matter.js/datatype";
31
+
32
+ const logger = Logger.get("Device");
33
+
34
+ requireMinNodeVersion(16);
35
+
36
+ /** Configure logging */
37
+ switch (getParameter("loglevel")) {
38
+ case "fatal":
39
+ Logger.defaultLogLevel = Level.FATAL;
40
+ break;
41
+ case "error":
42
+ Logger.defaultLogLevel = Level.ERROR;
43
+ break;
44
+ case "warn":
45
+ Logger.defaultLogLevel = Level.WARN;
46
+ break;
47
+ case "info":
48
+ Logger.defaultLogLevel = Level.INFO;
49
+ break;
50
+ }
51
+
52
+ switch (getParameter("logformat")) {
53
+ case "plain":
54
+ Logger.format = Format.PLAIN;
55
+ break;
56
+ case "html":
57
+ Logger.format = Format.HTML;
58
+ break;
59
+ default:
60
+ if (process.stdin?.isTTY) Logger.format = Format.ANSI;
61
+ }
62
+
63
+ const storageLocation = getParameter("store") ?? ".device-node";
64
+ const storage = new StorageBackendDisk(storageLocation, hasParameter("clearstorage"));
65
+ logger.info(`Storage location: ${storageLocation} (Directory)`);
66
+ logger.info(
67
+ 'Use the parameter "-store NAME" to specify a different storage location, use -clearstorage to start with an empty storage.',
68
+ );
69
+
70
+ class BridgedDevice {
71
+ private matterServer: MatterServer | undefined;
72
+
73
+ async start() {
74
+ logger.info(`node-matter`);
75
+
76
+ /**
77
+ * Initialize the storage system.
78
+ *
79
+ * The storage manager is then also used by the Matter server, so this code block in general is required,
80
+ * but you can choose a different storage backend as long as it implements the required API.
81
+ */
82
+
83
+ const storageManager = new StorageManager(storage);
84
+ await storageManager.initialize();
85
+
86
+ /**
87
+ * Collect all needed data
88
+ *
89
+ * This block makes sure to collect all needed data from cli or storage. Replace this with where ever your data
90
+ * come from.
91
+ *
92
+ * Note: This example also uses the initialized storage system to store the device parameter data for convenience
93
+ * and easy reuse. When you also do that be careful to not overlap with Matter-Server own contexts
94
+ * (so maybe better not ;-)).
95
+ */
96
+
97
+ const deviceStorage = storageManager.createContext("Device");
98
+
99
+ const deviceName = "Matter Bridge device";
100
+ const deviceType = DeviceTypes.AGGREGATOR.code;
101
+ const vendorName = "matter-node.js";
102
+ const passcode = getIntParameter("passcode") ?? deviceStorage.get("passcode", 20202021);
103
+ const discriminator = getIntParameter("discriminator") ?? deviceStorage.get("discriminator", 3840);
104
+ // product name / id and vendor id should match what is in the device certificate
105
+ const vendorId = getIntParameter("vendorid") ?? deviceStorage.get("vendorid", 0xfff1);
106
+ const productName = `node-matter OnOff-Bridge`;
107
+ const productId = getIntParameter("productid") ?? deviceStorage.get("productid", 0x8000);
108
+
109
+ const netAnnounceInterface = getParameter("announceinterface");
110
+ const port = getIntParameter("port") ?? 5540;
111
+
112
+ const uniqueId = getIntParameter("uniqueid") ?? deviceStorage.get("uniqueid", Time.nowMs());
113
+
114
+ deviceStorage.set("passcode", passcode);
115
+ deviceStorage.set("discriminator", discriminator);
116
+ deviceStorage.set("vendorid", vendorId);
117
+ deviceStorage.set("productid", productId);
118
+ deviceStorage.set("uniqueid", uniqueId);
119
+
120
+ /**
121
+ * Create Matter Server and CommissioningServer Node
122
+ *
123
+ * To allow the device to be announced, found, paired and operated we need a MatterServer instance and add a
124
+ * commissioningServer to it and add the just created device instance to it.
125
+ * The CommissioningServer node defines the port where the server listens for the UDP packages of the Matter protocol
126
+ * and initializes deice specific certificates and such.
127
+ *
128
+ * The below logic also adds command handlers for commands of clusters that normally are handled internally
129
+ * like testEventTrigger (General Diagnostic Cluster) that can be implemented with the logic when these commands
130
+ * are called.
131
+ */
132
+
133
+ this.matterServer = new MatterServer(storageManager, { mdnsAnnounceInterface: netAnnounceInterface });
134
+
135
+ const commissioningServer = new CommissioningServer({
136
+ port,
137
+ deviceName,
138
+ deviceType,
139
+ passcode,
140
+ discriminator,
141
+ basicInformation: {
142
+ vendorName,
143
+ vendorId: VendorId(vendorId),
144
+ nodeLabel: productName,
145
+ productName,
146
+ productLabel: productName,
147
+ productId,
148
+ serialNumber: `node-matter-${uniqueId}`,
149
+ },
150
+ });
151
+
152
+ /**
153
+ * Create Device instance and add needed Listener
154
+ *
155
+ * Create an instance of the matter device class you want to use.
156
+ * This example uses the OnOffLightDevice or OnOffPluginUnitDevice depending on the value of the type parameter.
157
+ * To execute the on/off scripts defined as parameters a listener for the onOff attribute is registered via the
158
+ * device specific API.
159
+ *
160
+ * The below logic also adds command handlers for commands of clusters that normally are handled device internally
161
+ * like identify that can be implemented with the logic when these commands are called.
162
+ */
163
+
164
+ const aggregator = new Aggregator();
165
+
166
+ const numDevices = getIntParameter("num") || 2;
167
+ for (let i = 1; i <= numDevices; i++) {
168
+ const onOffDevice =
169
+ getParameter(`type${i}`) === "socket" ? new OnOffPluginUnitDevice() : new OnOffLightDevice();
170
+
171
+ onOffDevice.addOnOffListener(on => commandExecutor(on ? `on${i}` : `off${i}`)?.());
172
+ onOffDevice.addCommandHandler("identify", async ({ request: { identifyTime } }) =>
173
+ console.log(
174
+ `Identify called for OnOffDevice ${onOffDevice.name} with id: ${i} and identifyTime: ${identifyTime}`,
175
+ ),
176
+ );
177
+
178
+ const name = `OnOff ${onOffDevice instanceof OnOffPluginUnitDevice ? "Socket" : "Light"} ${i}`;
179
+ aggregator.addBridgedDevice(onOffDevice, {
180
+ nodeLabel: name,
181
+ productName: name,
182
+ productLabel: name,
183
+ serialNumber: `node-matter-${uniqueId}-${i}`,
184
+ reachable: true,
185
+ });
186
+ }
187
+
188
+ commissioningServer.addDevice(aggregator);
189
+
190
+ this.matterServer.addCommissioningServer(commissioningServer);
191
+
192
+ /**
193
+ * Start the Matter Server
194
+ *
195
+ * After everything was plugged together we can start the server. When not delayed announcement is set for the
196
+ * CommissioningServer node then this command also starts the announcement of the device into the network.
197
+ */
198
+
199
+ await this.matterServer.start();
200
+
201
+ /**
202
+ * Print Pairing Information
203
+ *
204
+ * If the device is not already commissioned (this info is stored in the storage system) then get and print the
205
+ * pairing details. This includes the QR code that can be scanned by the Matter app to pair the device.
206
+ */
207
+
208
+ logger.info("Listening");
209
+ if (!commissioningServer.isCommissioned()) {
210
+ const pairingData = commissioningServer.getPairingCode();
211
+ const { qrCode, qrPairingCode, manualPairingCode } = pairingData;
212
+
213
+ console.log(qrCode);
214
+ console.log(
215
+ `QR Code URL: https://project-chip.github.io/connectedhomeip/qrcode.html?data=${qrPairingCode}`,
216
+ );
217
+ console.log(`Manual pairing code: ${manualPairingCode}`);
218
+ } else {
219
+ console.log("Device is already commissioned. Waiting for controllers to connect ...");
220
+ }
221
+ }
222
+
223
+ async stop() {
224
+ await this.matterServer?.close();
225
+ }
226
+ }
227
+
228
+ const device = new BridgedDevice();
229
+ device
230
+ .start()
231
+ .then(() => {
232
+ /* done */
233
+ })
234
+ .catch(err => console.error(err));
235
+
236
+ process.on("SIGINT", () => {
237
+ device
238
+ .stop()
239
+ .then(() => {
240
+ // Pragmatic way to make sure the storage is correctly closed before the process ends.
241
+ storage
242
+ .close()
243
+ .then(() => process.exit(0))
244
+ .catch(err => console.error(err));
245
+ })
246
+ .catch(err => console.error(err));
247
+ });
@@ -0,0 +1,245 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * @license
4
+ * Copyright 2022 The node-matter Authors
5
+ * SPDX-License-Identifier: Apache-2.0
6
+ */
7
+
8
+ /**
9
+ * This example shows how to create a new device node that is composed of multiple devices.
10
+ * It creates multiple endpoints on the server. When you want to add a composed devices to a Aggregator you need to
11
+ * add all endpoints of the composed device to an "ComposedDevice" instance! (not shown in this example).
12
+ * It can be used as CLI script and starting point for your own device node implementation.
13
+ */
14
+
15
+ /**
16
+ * Import needed modules from @project-chip/matter-node.js
17
+ */
18
+ // Include this first to auto-register Crypto, Network and Time Node.js implementations
19
+ import { CommissioningServer, MatterServer } from "@project-chip/matter-node.js";
20
+
21
+ import { VendorId } from "@project-chip/matter-node.js/datatype";
22
+ import { DeviceTypes, OnOffLightDevice, OnOffPluginUnitDevice } from "@project-chip/matter-node.js/device";
23
+ import { Format, Level, Logger } from "@project-chip/matter-node.js/log";
24
+ import { StorageBackendDisk, StorageManager } from "@project-chip/matter-node.js/storage";
25
+ import { Time } from "@project-chip/matter-node.js/time";
26
+ import {
27
+ commandExecutor,
28
+ getIntParameter,
29
+ getParameter,
30
+ hasParameter,
31
+ requireMinNodeVersion,
32
+ } from "@project-chip/matter-node.js/util";
33
+
34
+ const logger = Logger.get("Device");
35
+
36
+ requireMinNodeVersion(16);
37
+
38
+ /** Configure logging */
39
+ switch (getParameter("loglevel")) {
40
+ case "fatal":
41
+ Logger.defaultLogLevel = Level.FATAL;
42
+ break;
43
+ case "error":
44
+ Logger.defaultLogLevel = Level.ERROR;
45
+ break;
46
+ case "warn":
47
+ Logger.defaultLogLevel = Level.WARN;
48
+ break;
49
+ case "info":
50
+ Logger.defaultLogLevel = Level.INFO;
51
+ break;
52
+ }
53
+
54
+ switch (getParameter("logformat")) {
55
+ case "plain":
56
+ Logger.format = Format.PLAIN;
57
+ break;
58
+ case "html":
59
+ Logger.format = Format.HTML;
60
+ break;
61
+ default:
62
+ if (process.stdin?.isTTY) Logger.format = Format.ANSI;
63
+ }
64
+
65
+ const storageLocation = getParameter("store") ?? ".device-node";
66
+ const storage = new StorageBackendDisk(storageLocation, hasParameter("clearstorage"));
67
+ logger.info(`Storage location: ${storageLocation} (Directory)`);
68
+ logger.info(
69
+ 'Use the parameter "-store NAME" to specify a different storage location, use -clearstorage to start with an empty storage.',
70
+ );
71
+
72
+ class ComposedDevice {
73
+ private matterServer: MatterServer | undefined;
74
+
75
+ async start() {
76
+ logger.info(`node-matter`);
77
+
78
+ /**
79
+ * Initialize the storage system.
80
+ *
81
+ * The storage manager is then also used by the Matter server, so this code block in general is required,
82
+ * but you can choose a different storage backend as long as it implements the required API.
83
+ */
84
+
85
+ const storageManager = new StorageManager(storage);
86
+ await storageManager.initialize();
87
+
88
+ /**
89
+ * Collect all needed data
90
+ *
91
+ * This block makes sure to collect all needed data from cli or storage. Replace this with where ever your data
92
+ * come from.
93
+ *
94
+ * Note: This example also uses the initialized storage system to store the device parameter data for convenience
95
+ * and easy reuse. When you also do that be careful to not overlap with Matter-Server own contexts
96
+ * (so maybe better not ;-)).
97
+ */
98
+
99
+ const deviceStorage = storageManager.createContext("Device");
100
+
101
+ if (deviceStorage.has("isSocket")) {
102
+ logger.info("Device type found in storage. -type parameter is ignored.");
103
+ }
104
+ const isSocket = deviceStorage.get("isSocket", getParameter("type") === "socket");
105
+ const deviceName = "Matter composed device";
106
+ const deviceType =
107
+ getParameter("type") === "socket" ? DeviceTypes.ON_OFF_PLUGIN_UNIT.code : DeviceTypes.ON_OFF_LIGHT.code;
108
+ const vendorName = "matter-node.js";
109
+ const passcode = getIntParameter("passcode") ?? deviceStorage.get("passcode", 20202021);
110
+ const discriminator = getIntParameter("discriminator") ?? deviceStorage.get("discriminator", 3840);
111
+ // product name / id and vendor id should match what is in the device certificate
112
+ const vendorId = getIntParameter("vendorid") ?? deviceStorage.get("vendorid", 0xfff1);
113
+ const productName = `node-matter OnOff-Bridge`;
114
+ const productId = getIntParameter("productid") ?? deviceStorage.get("productid", 0x8000);
115
+
116
+ const netAnnounceInterface = getParameter("announceinterface");
117
+ const port = getIntParameter("port") ?? 5540;
118
+
119
+ const uniqueId = getIntParameter("uniqueid") ?? deviceStorage.get("uniqueid", Time.nowMs());
120
+
121
+ deviceStorage.set("passcode", passcode);
122
+ deviceStorage.set("discriminator", discriminator);
123
+ deviceStorage.set("vendorid", vendorId);
124
+ deviceStorage.set("productid", productId);
125
+ deviceStorage.set("isSocket", isSocket);
126
+ deviceStorage.set("uniqueid", uniqueId);
127
+
128
+ /**
129
+ * Create Matter Server and CommissioningServer Node
130
+ *
131
+ * To allow the device to be announced, found, paired and operated we need a MatterServer instance and add a
132
+ * commissioningServer to it and add the just created device instance to it.
133
+ * The CommissioningServer node defines the port where the server listens for the UDP packages of the Matter protocol
134
+ * and initializes deice specific certificates and such.
135
+ *
136
+ * The below logic also adds command handlers for commands of clusters that normally are handled internally
137
+ * like testEventTrigger (General Diagnostic Cluster) that can be implemented with the logic when these commands
138
+ * are called.
139
+ */
140
+
141
+ this.matterServer = new MatterServer(storageManager, { mdnsAnnounceInterface: netAnnounceInterface });
142
+
143
+ const commissioningServer = new CommissioningServer({
144
+ port,
145
+ deviceName,
146
+ deviceType,
147
+ passcode,
148
+ discriminator,
149
+ basicInformation: {
150
+ vendorName,
151
+ vendorId: VendorId(vendorId),
152
+ nodeLabel: productName,
153
+ productName,
154
+ productLabel: productName,
155
+ productId,
156
+ serialNumber: `node-matter-${uniqueId}`,
157
+ },
158
+ });
159
+
160
+ /**
161
+ * Create Device instance and add needed Listener
162
+ *
163
+ * Create an instance of the matter device class you want to use.
164
+ * This example uses the OnOffLightDevice or OnOffPluginUnitDevice depending on the value of the type parameter.
165
+ * To execute the on/off scripts defined as parameters a listener for the onOff attribute is registered via the
166
+ * device specific API.
167
+ *
168
+ * The below logic also adds command handlers for commands of clusters that normally are handled device internally
169
+ * like identify that can be implemented with the logic when these commands are called.
170
+ */
171
+
172
+ const numDevices = getIntParameter("num") || 2;
173
+ for (let i = 1; i <= numDevices; i++) {
174
+ const onOffDevice =
175
+ getParameter(`type${i}`) === "socket" ? new OnOffPluginUnitDevice() : new OnOffLightDevice();
176
+ onOffDevice.addFixedLabel("orientation", getParameter(`orientation${i}`) ?? `orientation ${i}`);
177
+
178
+ onOffDevice.addOnOffListener(on => commandExecutor(on ? `on${i}` : `off${i}`)?.());
179
+ onOffDevice.addCommandHandler("identify", async ({ request: { identifyTime } }) =>
180
+ console.log(
181
+ `Identify called for OnOffDevice ${onOffDevice.name} with id: ${i} and identifyTime: ${identifyTime}`,
182
+ ),
183
+ );
184
+
185
+ commissioningServer.addDevice(onOffDevice);
186
+ }
187
+
188
+ this.matterServer.addCommissioningServer(commissioningServer);
189
+
190
+ /**
191
+ * Start the Matter Server
192
+ *
193
+ * After everything was plugged together we can start the server. When not delayed announcement is set for the
194
+ * CommissioningServer node then this command also starts the announcement of the device into the network.
195
+ */
196
+
197
+ await this.matterServer.start();
198
+
199
+ /**
200
+ * Print Pairing Information
201
+ *
202
+ * If the device is not already commissioned (this info is stored in the storage system) then get and print the
203
+ * pairing details. This includes the QR code that can be scanned by the Matter app to pair the device.
204
+ */
205
+
206
+ logger.info("Listening");
207
+ if (!commissioningServer.isCommissioned()) {
208
+ const pairingData = commissioningServer.getPairingCode();
209
+ const { qrCode, qrPairingCode, manualPairingCode } = pairingData;
210
+
211
+ console.log(qrCode);
212
+ console.log(
213
+ `QR Code URL: https://project-chip.github.io/connectedhomeip/qrcode.html?data=${qrPairingCode}`,
214
+ );
215
+ console.log(`Manual pairing code: ${manualPairingCode}`);
216
+ } else {
217
+ console.log("Device is already commissioned. Waiting for controllers to connect ...");
218
+ }
219
+ }
220
+
221
+ async stop() {
222
+ await this.matterServer?.close();
223
+ }
224
+ }
225
+
226
+ const device = new ComposedDevice();
227
+ device
228
+ .start()
229
+ .then(() => {
230
+ /* done */
231
+ })
232
+ .catch(err => console.error(err));
233
+
234
+ process.on("SIGINT", () => {
235
+ device
236
+ .stop()
237
+ .then(() => {
238
+ // Pragmatic way to make sure the storage is correctly closed before the process ends.
239
+ storage
240
+ .close()
241
+ .then(() => process.exit(0))
242
+ .catch(err => console.error(err));
243
+ })
244
+ .catch(err => console.error(err));
245
+ });