@project-chip/matter-node.js-examples 0.7.5-alpha.0-20240222-8696097f → 0.8.0-alpha.1-20240308-033110a3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. package/README.md +44 -0
  2. package/dist/esm/examples/BridgedDeviceNode.js +147 -0
  3. package/dist/esm/examples/BridgedDeviceNode.js.map +7 -0
  4. package/dist/esm/examples/{BridgedDevicesNode.js → BridgedDevicesNodeLegacy.js} +2 -2
  5. package/dist/esm/examples/BridgedDevicesNodeLegacy.js.map +7 -0
  6. package/dist/esm/examples/ComposedDeviceNode.js +116 -127
  7. package/dist/esm/examples/ComposedDeviceNode.js.map +3 -3
  8. package/dist/esm/examples/ComposedDeviceNodeLegacy.js +138 -0
  9. package/dist/esm/examples/ComposedDeviceNodeLegacy.js.map +7 -0
  10. package/dist/esm/examples/ControllerNode.js +24 -20
  11. package/dist/esm/examples/ControllerNode.js.map +2 -2
  12. package/dist/esm/examples/ControllerNodeLegacy.js +227 -0
  13. package/dist/esm/examples/ControllerNodeLegacy.js.map +7 -0
  14. package/dist/esm/examples/DeviceNode.js +118 -159
  15. package/dist/esm/examples/DeviceNode.js.map +2 -2
  16. package/dist/esm/examples/DeviceNodeFull.js +253 -0
  17. package/dist/esm/examples/DeviceNodeFull.js.map +7 -0
  18. package/dist/esm/examples/DeviceNodeFullLegacy.js +171 -0
  19. package/dist/esm/examples/DeviceNodeFullLegacy.js.map +7 -0
  20. package/dist/esm/examples/IlluminatedRollerShade.js +85 -0
  21. package/dist/esm/examples/IlluminatedRollerShade.js.map +7 -0
  22. package/dist/esm/examples/LightDevice.js +34 -0
  23. package/dist/esm/examples/LightDevice.js.map +7 -0
  24. package/dist/esm/examples/MultiDeviceNode.js +133 -134
  25. package/dist/esm/examples/MultiDeviceNode.js.map +3 -3
  26. package/dist/esm/examples/MultiDeviceNodeLegacy.js +146 -0
  27. package/dist/esm/examples/MultiDeviceNodeLegacy.js.map +7 -0
  28. package/dist/esm/examples/SensorDeviceNode.js +167 -0
  29. package/dist/esm/examples/SensorDeviceNode.js.map +7 -0
  30. package/dist/esm/examples/cluster/DummyThreadNetworkCommissioningServer.js +115 -0
  31. package/dist/esm/examples/cluster/DummyThreadNetworkCommissioningServer.js.map +7 -0
  32. package/dist/esm/examples/cluster/DummyWifiNetworkCommissioningServer.js +115 -0
  33. package/dist/esm/examples/cluster/DummyWifiNetworkCommissioningServer.js.map +7 -0
  34. package/dist/esm/examples/cluster/{DummyWifiNetworkCommissioningClusterServer.js → DummyWifiNetworkCommissioningServerLegacy.js} +16 -14
  35. package/dist/esm/examples/cluster/DummyWifiNetworkCommissioningServerLegacy.js.map +7 -0
  36. package/dist/esm/examples/cluster/MyFancyOwnFunctionality.js +110 -0
  37. package/dist/esm/examples/cluster/MyFancyOwnFunctionality.js.map +7 -0
  38. package/dist/esm/tutorial/example01.js +5 -0
  39. package/dist/esm/tutorial/example01.js.map +7 -0
  40. package/dist/esm/tutorial/example02.js +7 -0
  41. package/dist/esm/tutorial/example02.js.map +7 -0
  42. package/dist/esm/tutorial/example03.js +15 -0
  43. package/dist/esm/tutorial/example03.js.map +7 -0
  44. package/dist/esm/tutorial/example04.js +10 -0
  45. package/dist/esm/tutorial/example04.js.map +7 -0
  46. package/dist/esm/tutorial/example05.js +14 -0
  47. package/dist/esm/tutorial/example05.js.map +7 -0
  48. package/package.json +9 -6
  49. package/src/examples/BridgedDeviceNode.ts +260 -0
  50. package/src/examples/{BridgedDevicesNode.ts → BridgedDevicesNodeLegacy.ts} +6 -1
  51. package/src/examples/ComposedDeviceNode.ts +173 -223
  52. package/src/examples/ComposedDeviceNodeLegacy.ts +252 -0
  53. package/src/examples/ControllerNode.ts +28 -22
  54. package/src/examples/ControllerNodeLegacy.ts +354 -0
  55. package/src/examples/DeviceNode.ts +173 -273
  56. package/src/examples/DeviceNodeFull.ts +440 -0
  57. package/src/examples/DeviceNodeFullLegacy.ts +307 -0
  58. package/src/examples/IlluminatedRollerShade.ts +130 -0
  59. package/src/examples/LightDevice.ts +60 -0
  60. package/src/examples/MultiDeviceNode.ts +184 -236
  61. package/src/examples/MultiDeviceNodeLegacy.ts +267 -0
  62. package/src/examples/SensorDeviceNode.ts +236 -0
  63. package/src/examples/cluster/DummyThreadNetworkCommissioningServer.ts +156 -0
  64. package/src/examples/cluster/DummyWifiNetworkCommissioningServer.ts +153 -0
  65. package/src/examples/cluster/{DummyWifiNetworkCommissioningClusterServer.ts → DummyWifiNetworkCommissioningServerLegacy.ts} +16 -13
  66. package/src/examples/cluster/MyFancyOwnFunctionality.ts +185 -0
  67. package/src/tsconfig.json +9 -1
  68. package/src/tutorial/example01.ts +6 -0
  69. package/src/tutorial/example02.ts +9 -0
  70. package/src/tutorial/example03.ts +19 -0
  71. package/src/tutorial/example04.ts +13 -0
  72. package/src/tutorial/example05.ts +19 -0
  73. package/dist/esm/examples/BridgedDevicesNode.js.map +0 -7
  74. package/dist/esm/examples/cluster/DummyWifiNetworkCommissioningClusterServer.js.map +0 -7
@@ -2,7 +2,7 @@
2
2
 
3
3
  /**
4
4
  * @license
5
- * Copyright 2022-2023 Project CHIP Authors
5
+ * Copyright 2022-2024 Matter.js Authors
6
6
  * SPDX-License-Identifier: Apache-2.0
7
7
  */
8
8
 
@@ -16,29 +16,29 @@
16
16
  * Import needed modules from @project-chip/matter-node.js
17
17
  */
18
18
  // Include this first to auto-register Crypto, Network and Time Node.js implementations
19
- import { CommissioningController, MatterServer, NodeCommissioningOptions } from "@project-chip/matter-node.js";
19
+ // Include this first to auto-register Crypto, Network and Time Node.js implementations
20
+ import "@project-chip/matter-node.js";
20
21
 
21
22
  import { BleNode } from "@project-chip/matter-node-ble.js/ble";
22
- import { Ble } from "@project-chip/matter-node.js/ble";
23
+ import { StorageBackendDisk } from "@project-chip/matter-node.js/storage";
24
+ import { getIntParameter, getParameter, hasParameter, requireMinNodeVersion } from "@project-chip/matter-node.js/util";
25
+ import { CommissioningController, NodeCommissioningOptions } from "@project-chip/matter.js";
26
+ import { Ble } from "@project-chip/matter.js/ble";
23
27
  import {
24
28
  BasicInformationCluster,
25
29
  DescriptorCluster,
26
30
  GeneralCommissioning,
27
31
  OnOffCluster,
28
- } from "@project-chip/matter-node.js/cluster";
29
- import { NodeId } from "@project-chip/matter-node.js/datatype";
30
- import { NodeStateInformation } from "@project-chip/matter-node.js/device";
31
- import { Format, Level, Logger } from "@project-chip/matter-node.js/log";
32
- import { CommissioningOptions } from "@project-chip/matter-node.js/protocol";
33
- import { ManualPairingCodeCodec } from "@project-chip/matter-node.js/schema";
34
- import { StorageBackendDisk, StorageManager } from "@project-chip/matter-node.js/storage";
35
- import {
36
- getIntParameter,
37
- getParameter,
38
- hasParameter,
39
- requireMinNodeVersion,
40
- singleton,
41
- } from "@project-chip/matter-node.js/util";
32
+ } from "@project-chip/matter.js/cluster";
33
+ import { NodeId } from "@project-chip/matter.js/datatype";
34
+ import { NodeStateInformation } from "@project-chip/matter.js/device";
35
+ import { Environment } from "@project-chip/matter.js/environment";
36
+ import { Format, Level, Logger } from "@project-chip/matter.js/log";
37
+ import { CommissioningOptions } from "@project-chip/matter.js/protocol";
38
+ import { ManualPairingCodeCodec } from "@project-chip/matter.js/schema";
39
+ import { StorageManager } from "@project-chip/matter.js/storage";
40
+ import { Time } from "@project-chip/matter.js/time";
41
+ import { singleton } from "@project-chip/matter.js/util";
42
42
 
43
43
  const logger = Logger.get("Controller");
44
44
 
@@ -116,6 +116,10 @@ class ControllerNode {
116
116
  const controllerStorage = storageManager.createContext("Controller");
117
117
  const ip = controllerStorage.has("ip") ? controllerStorage.get<string>("ip") : getParameter("ip");
118
118
  const port = controllerStorage.has("port") ? controllerStorage.get<number>("port") : getIntParameter("port");
119
+ const uniqueId = controllerStorage.has("uniqueid")
120
+ ? controllerStorage.get<string>("uniqueid")
121
+ : getParameter("uniqueid") ?? Time.nowMs().toString();
122
+ controllerStorage.set("uniqueid", uniqueId);
119
123
 
120
124
  const pairingCode = getParameter("pairingcode");
121
125
  let longDiscriminator, setupPin, shortDiscriminator;
@@ -179,11 +183,14 @@ class ControllerNode {
179
183
  * are called.
180
184
  */
181
185
 
182
- const matterServer = new MatterServer(storageManager);
186
+ const environment = Environment.default;
183
187
  const commissioningController = new CommissioningController({
188
+ environment: {
189
+ environment,
190
+ id: uniqueId,
191
+ },
184
192
  autoConnect: false,
185
193
  });
186
- await matterServer.addCommissioningController(commissioningController);
187
194
 
188
195
  /**
189
196
  * Start the Matter Server
@@ -191,8 +198,7 @@ class ControllerNode {
191
198
  * After everything was plugged together we can start the server. When not delayed announcement is set for the
192
199
  * CommissioningServer node then this command also starts the announcement of the device into the network.
193
200
  */
194
-
195
- await matterServer.start();
201
+ await commissioningController.start();
196
202
 
197
203
  if (!commissioningController.isCommissioned()) {
198
204
  const options = {
@@ -308,7 +314,7 @@ class ControllerNode {
308
314
  //console.log("Attributes-BasicInformation:", JSON.stringify(attributesBasicInformation, null, 2));
309
315
 
310
316
  const devices = node.getDevices();
311
- if (devices[0] && devices[0].id === 1) {
317
+ if (devices[0] && devices[0].number === 1) {
312
318
  // Example to subscribe to all Attributes of endpoint 1 of the commissioned node: */*/*
313
319
  //await interactionClient.subscribeMultipleAttributes([{ endpointId: 1, /* subscribe anything from endpoint 1 */ }], 0, 180, data => {
314
320
  // console.log("Subscribe-All Data:", Logger.toJSON(data));
@@ -0,0 +1,354 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * @license
5
+ * Copyright 2022-2023 Project CHIP Authors
6
+ * SPDX-License-Identifier: Apache-2.0
7
+ */
8
+
9
+ /**
10
+ * This example shows how to create a Matter controller to pair with a device and interfact with it.
11
+ * It can be used as CLI script, but is more thought as a starting point for your own controller implementation
12
+ * because you need to adjust the code in any way depending on your use case.
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 { CommissioningController, MatterServer, NodeCommissioningOptions } from "@project-chip/matter-node.js";
20
+
21
+ import { BleNode } from "@project-chip/matter-node-ble.js/ble";
22
+ import { Ble } from "@project-chip/matter-node.js/ble";
23
+ import {
24
+ BasicInformationCluster,
25
+ DescriptorCluster,
26
+ GeneralCommissioning,
27
+ OnOffCluster,
28
+ } from "@project-chip/matter-node.js/cluster";
29
+ import { NodeId } from "@project-chip/matter-node.js/datatype";
30
+ import { NodeStateInformation } from "@project-chip/matter-node.js/device";
31
+ import { Format, Level, Logger } from "@project-chip/matter-node.js/log";
32
+ import { CommissioningOptions } from "@project-chip/matter-node.js/protocol";
33
+ import { ManualPairingCodeCodec } from "@project-chip/matter-node.js/schema";
34
+ import { StorageBackendDisk, StorageManager } from "@project-chip/matter-node.js/storage";
35
+ import {
36
+ getIntParameter,
37
+ getParameter,
38
+ hasParameter,
39
+ requireMinNodeVersion,
40
+ singleton,
41
+ } from "@project-chip/matter-node.js/util";
42
+
43
+ const logger = Logger.get("Controller");
44
+
45
+ requireMinNodeVersion(16);
46
+
47
+ /** Configure logging */
48
+ switch (getParameter("loglevel")) {
49
+ case "fatal":
50
+ Logger.defaultLogLevel = Level.FATAL;
51
+ break;
52
+ case "error":
53
+ Logger.defaultLogLevel = Level.ERROR;
54
+ break;
55
+ case "warn":
56
+ Logger.defaultLogLevel = Level.WARN;
57
+ break;
58
+ case "info":
59
+ Logger.defaultLogLevel = Level.INFO;
60
+ break;
61
+ }
62
+
63
+ switch (getParameter("logformat")) {
64
+ case "plain":
65
+ Logger.format = Format.PLAIN;
66
+ break;
67
+ case "html":
68
+ Logger.format = Format.HTML;
69
+ break;
70
+ default:
71
+ if (process.stdin?.isTTY) Logger.format = Format.ANSI;
72
+ }
73
+
74
+ if (hasParameter("ble")) {
75
+ // Initialize Ble
76
+ Ble.get = singleton(
77
+ () =>
78
+ new BleNode({
79
+ hciId: getIntParameter("ble-hci-id"),
80
+ }),
81
+ );
82
+ }
83
+
84
+ const storageLocation = getParameter("store") ?? ".controller-node";
85
+ const storage = new StorageBackendDisk(storageLocation, hasParameter("clearstorage"));
86
+ logger.info(`Storage location: ${storageLocation} (Directory)`);
87
+ logger.info(
88
+ 'Use the parameter "-store NAME" to specify a different storage location, use -clearstorage to start with an empty storage.',
89
+ );
90
+
91
+ class ControllerNode {
92
+ async start() {
93
+ logger.info(`node-matter Controller started`);
94
+
95
+ /**
96
+ * Initialize the storage system.
97
+ *
98
+ * The storage manager is then also used by the Matter server, so this code block in general is required,
99
+ * but you can choose a different storage backend as long as it implements the required API.
100
+ */
101
+
102
+ const storageManager = new StorageManager(storage);
103
+ await storageManager.initialize();
104
+
105
+ /**
106
+ * Collect all needed data
107
+ *
108
+ * This block makes sure to collect all needed data from cli or storage. Replace this with where ever your data
109
+ * come from.
110
+ *
111
+ * Note: This example also uses the initialized storage system to store the device parameter data for convenience
112
+ * and easy reuse. When you also do that be careful to not overlap with Matter-Server own contexts
113
+ * (so maybe better not ;-)).
114
+ */
115
+
116
+ const controllerStorage = storageManager.createContext("Controller");
117
+ const ip = controllerStorage.has("ip") ? controllerStorage.get<string>("ip") : getParameter("ip");
118
+ const port = controllerStorage.has("port") ? controllerStorage.get<number>("port") : getIntParameter("port");
119
+
120
+ const pairingCode = getParameter("pairingcode");
121
+ let longDiscriminator, setupPin, shortDiscriminator;
122
+ if (pairingCode !== undefined) {
123
+ const pairingCodeCodec = ManualPairingCodeCodec.decode(pairingCode);
124
+ shortDiscriminator = pairingCodeCodec.shortDiscriminator;
125
+ longDiscriminator = undefined;
126
+ setupPin = pairingCodeCodec.passcode;
127
+ logger.debug(`Data extracted from pairing code: ${Logger.toJSON(pairingCodeCodec)}`);
128
+ } else {
129
+ longDiscriminator =
130
+ getIntParameter("longDiscriminator") ?? controllerStorage.get("longDiscriminator", 3840);
131
+ if (longDiscriminator > 4095) throw new Error("Discriminator value must be less than 4096");
132
+ setupPin = getIntParameter("pin") ?? controllerStorage.get("pin", 20202021);
133
+ }
134
+ if ((shortDiscriminator === undefined && longDiscriminator === undefined) || setupPin === undefined) {
135
+ throw new Error(
136
+ "Please specify the longDiscriminator of the device to commission with -longDiscriminator or provide a valid passcode with -passcode",
137
+ );
138
+ }
139
+
140
+ // Collect commissioning options from commandline parameters
141
+ const commissioningOptions: CommissioningOptions = {
142
+ regulatoryLocation: GeneralCommissioning.RegulatoryLocationType.IndoorOutdoor,
143
+ regulatoryCountryCode: "XX",
144
+ };
145
+
146
+ let ble = false;
147
+ if (hasParameter("ble")) {
148
+ ble = true;
149
+ const wifiSsid = getParameter("ble-wifi-ssid");
150
+ const wifiCredentials = getParameter("ble-wifi-credentials");
151
+ const threadNetworkName = getParameter("ble-thread-networkname");
152
+ const threadOperationalDataset = getParameter("ble-thread-operationaldataset");
153
+ if (wifiSsid !== undefined && wifiCredentials !== undefined) {
154
+ logger.info(`Registering Commissioning over BLE with WiFi: ${wifiSsid}`);
155
+ commissioningOptions.wifiNetwork = {
156
+ wifiSsid: wifiSsid,
157
+ wifiCredentials: wifiCredentials,
158
+ };
159
+ }
160
+ if (threadNetworkName !== undefined && threadOperationalDataset !== undefined) {
161
+ logger.info(`Registering Commissioning over BLE with Thread: ${threadNetworkName}`);
162
+ commissioningOptions.threadNetwork = {
163
+ networkName: threadNetworkName,
164
+ operationalDataset: threadOperationalDataset,
165
+ };
166
+ }
167
+ }
168
+
169
+ /**
170
+ * Create Matter Server and Controller Node
171
+ *
172
+ * To allow the device to be announced, found, paired and operated we need a MatterServer instance and add a
173
+ * CommissioningController to it and add the just created device instance to it.
174
+ * The Controller node defines the port where the server listens for the UDP packages of the Matter protocol
175
+ * and initializes deice specific certificates and such.
176
+ *
177
+ * The below logic also adds command handlers for commands of clusters that normally are handled internally
178
+ * like testEventTrigger (General Diagnostic Cluster) that can be implemented with the logic when these commands
179
+ * are called.
180
+ */
181
+
182
+ const matterServer = new MatterServer(storageManager);
183
+ const commissioningController = new CommissioningController({
184
+ autoConnect: false,
185
+ });
186
+ await matterServer.addCommissioningController(commissioningController);
187
+
188
+ /**
189
+ * Start the Matter Server
190
+ *
191
+ * After everything was plugged together we can start the server. When not delayed announcement is set for the
192
+ * CommissioningServer node then this command also starts the announcement of the device into the network.
193
+ */
194
+
195
+ await matterServer.start();
196
+
197
+ if (!commissioningController.isCommissioned()) {
198
+ const options = {
199
+ commissioning: commissioningOptions,
200
+ discovery: {
201
+ knownAddress: ip !== undefined && port !== undefined ? { ip, port, type: "udp" } : undefined,
202
+ identifierData:
203
+ longDiscriminator !== undefined
204
+ ? { longDiscriminator }
205
+ : shortDiscriminator !== undefined
206
+ ? { shortDiscriminator }
207
+ : {},
208
+ discoveryCapabilities: {
209
+ ble,
210
+ },
211
+ },
212
+ passcode: setupPin,
213
+ } as NodeCommissioningOptions;
214
+ logger.info(`Commissioning ... ${JSON.stringify(options)}`);
215
+ const nodeId = await commissioningController.commissionNode(options);
216
+
217
+ console.log(`Commissioning successfully done with nodeId ${nodeId}`);
218
+ }
219
+
220
+ /**
221
+ * TBD
222
+ */
223
+ try {
224
+ const nodes = commissioningController.getCommissionedNodes();
225
+ console.log("Found commissioned nodes:", Logger.toJSON(nodes));
226
+
227
+ const nodeId = NodeId(getIntParameter("nodeid") ?? nodes[0]);
228
+ if (!nodes.includes(nodeId)) {
229
+ throw new Error(`Node ${nodeId} not found in commissioned nodes`);
230
+ }
231
+
232
+ const node = await commissioningController.connectNode(nodeId, {
233
+ attributeChangedCallback: (
234
+ peerNodeId,
235
+ { path: { nodeId, clusterId, endpointId, attributeName }, value },
236
+ ) =>
237
+ console.log(
238
+ `attributeChangedCallback ${peerNodeId}: Attribute ${nodeId}/${endpointId}/${clusterId}/${attributeName} changed to ${Logger.toJSON(
239
+ value,
240
+ )}`,
241
+ ),
242
+ eventTriggeredCallback: (peerNodeId, { path: { nodeId, clusterId, endpointId, eventName }, events }) =>
243
+ console.log(
244
+ `eventTriggeredCallback ${peerNodeId}: Event ${nodeId}/${endpointId}/${clusterId}/${eventName} triggered with ${Logger.toJSON(
245
+ events,
246
+ )}`,
247
+ ),
248
+ stateInformationCallback: (peerNodeId, info) => {
249
+ switch (info) {
250
+ case NodeStateInformation.Connected:
251
+ console.log(`stateInformationCallback ${peerNodeId}: Node ${nodeId} connected`);
252
+ break;
253
+ case NodeStateInformation.Disconnected:
254
+ console.log(`stateInformationCallback ${peerNodeId}: Node ${nodeId} disconnected`);
255
+ break;
256
+ case NodeStateInformation.Reconnecting:
257
+ console.log(`stateInformationCallback ${peerNodeId}: Node ${nodeId} reconnecting`);
258
+ break;
259
+ case NodeStateInformation.WaitingForDeviceDiscovery:
260
+ console.log(
261
+ `stateInformationCallback ${peerNodeId}: Node ${nodeId} waiting for device discovery`,
262
+ );
263
+ break;
264
+ case NodeStateInformation.StructureChanged:
265
+ console.log(`stateInformationCallback ${peerNodeId}: Node ${nodeId} structure changed`);
266
+ break;
267
+ case NodeStateInformation.Decommissioned:
268
+ console.log(`stateInformationCallback ${peerNodeId}: Node ${nodeId} decommissioned`);
269
+ break;
270
+ }
271
+ },
272
+ });
273
+
274
+ // Important: This is a temporary API to proof the methods working and this will change soon and is NOT stable!
275
+ // It is provided to proof the concept
276
+
277
+ node.logStructure();
278
+
279
+ // Example to initialize a ClusterClient and access concrete fields as API methods
280
+ const descriptor = node.getRootClusterClient(DescriptorCluster);
281
+ if (descriptor !== undefined) {
282
+ console.log(await descriptor.attributes.deviceTypeList.get()); // you can call that way
283
+ console.log(await descriptor.getServerListAttribute()); // or more convenient that way
284
+ } else {
285
+ console.log("No Descriptor Cluster found. This should never happen!");
286
+ }
287
+
288
+ // Example to subscribe to a field and get the value
289
+ const info = node.getRootClusterClient(BasicInformationCluster);
290
+ if (info !== undefined) {
291
+ console.log(await info.getProductNameAttribute()); // This call is executed remotely
292
+ //console.log(await info.subscribeProductNameAttribute(value => console.log("productName", value), 5, 30));
293
+ //console.log(await info.getProductNameAttribute()); // This call is resolved locally because we have subscribed to the value!
294
+ } else {
295
+ console.log("No BasicInformation Cluster found. This should never happen!");
296
+ }
297
+
298
+ // Example to get all Attributes of the commissioned node: */*/*
299
+ //const attributesAll = await interactionClient.getAllAttributes();
300
+ //console.log("Attributes-All:", Logger.toJSON(attributesAll));
301
+
302
+ // Example to get all Attributes of all Descriptor Clusters of the commissioned node: */DescriptorCluster/*
303
+ //const attributesAllDescriptor = await interactionClient.getMultipleAttributes([{ clusterId: DescriptorCluster.id} ]);
304
+ //console.log("Attributes-Descriptor:", JSON.stringify(attributesAllDescriptor, null, 2));
305
+
306
+ // Example to get all Attributes of the Basic Information Cluster of endpoint 0 of the commissioned node: 0/BasicInformationCluster/*
307
+ //const attributesBasicInformation = await interactionClient.getMultipleAttributes([{ endpointId: 0, clusterId: BasicInformationCluster.id} ]);
308
+ //console.log("Attributes-BasicInformation:", JSON.stringify(attributesBasicInformation, null, 2));
309
+
310
+ const devices = node.getDevices();
311
+ if (devices[0] && devices[0].number === 1) {
312
+ // Example to subscribe to all Attributes of endpoint 1 of the commissioned node: */*/*
313
+ //await interactionClient.subscribeMultipleAttributes([{ endpointId: 1, /* subscribe anything from endpoint 1 */ }], 0, 180, data => {
314
+ // console.log("Subscribe-All Data:", Logger.toJSON(data));
315
+ //});
316
+
317
+ const onOff = devices[0].getClusterClient(OnOffCluster);
318
+ if (onOff !== undefined) {
319
+ let onOffStatus = await onOff.getOnOffAttribute();
320
+ console.log("initial onOffStatus", onOffStatus);
321
+
322
+ onOff.addOnOffAttributeListener(value => {
323
+ console.log("subscription onOffStatus", value);
324
+ onOffStatus = value;
325
+ });
326
+ // read data every minute to keep up the connection to show the subscription is working
327
+ setInterval(() => {
328
+ onOff
329
+ .toggle()
330
+ .then(() => {
331
+ onOffStatus = !onOffStatus;
332
+ console.log("onOffStatus", onOffStatus);
333
+ })
334
+ .catch(error => logger.error(error));
335
+ }, 60000);
336
+ }
337
+ }
338
+ } finally {
339
+ //await matterServer.close(); // Comment out when subscribes are used, else the connection will be closed
340
+ setTimeout(() => process.exit(0), 1000000);
341
+ }
342
+ }
343
+ }
344
+
345
+ new ControllerNode().start().catch(error => logger.error(error));
346
+
347
+ process.on("SIGINT", () => {
348
+ // Clean up on CTRL-C
349
+ // Pragmatic way to make sure the storage is correctly closed before the process ends.
350
+ storage
351
+ .close()
352
+ .then(() => process.exit(0))
353
+ .catch(() => process.exit(1));
354
+ });