@project-chip/matter-node.js-examples 0.8.0-alpha.1-20240308-033110a3 → 0.8.1-alpha.0-20240401-c87f2ece

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. package/README.md +17 -0
  2. package/dist/esm/examples/{BridgedDeviceNode.js → BridgedDevicesNode.js} +21 -23
  3. package/dist/esm/examples/BridgedDevicesNode.js.map +7 -0
  4. package/dist/esm/examples/BridgedDevicesNodeLegacy.js +9 -6
  5. package/dist/esm/examples/BridgedDevicesNodeLegacy.js.map +2 -2
  6. package/dist/esm/examples/ComposedDeviceNode.js +20 -22
  7. package/dist/esm/examples/ComposedDeviceNode.js.map +2 -2
  8. package/dist/esm/examples/ComposedDeviceNodeLegacy.js +10 -7
  9. package/dist/esm/examples/ComposedDeviceNodeLegacy.js.map +2 -2
  10. package/dist/esm/examples/ControllerNode.js +23 -56
  11. package/dist/esm/examples/ControllerNode.js.map +2 -2
  12. package/dist/esm/examples/ControllerNodeLegacy.js +2 -1
  13. package/dist/esm/examples/ControllerNodeLegacy.js.map +2 -2
  14. package/dist/esm/examples/DeviceNode.js +20 -22
  15. package/dist/esm/examples/DeviceNode.js.map +2 -2
  16. package/dist/esm/examples/DeviceNodeFull.js +22 -24
  17. package/dist/esm/examples/DeviceNodeFull.js.map +2 -2
  18. package/dist/esm/examples/DeviceNodeFullLegacy.js +10 -7
  19. package/dist/esm/examples/DeviceNodeFullLegacy.js.map +2 -2
  20. package/dist/esm/examples/LegacyStorageConverter.js +126 -0
  21. package/dist/esm/examples/LegacyStorageConverter.js.map +7 -0
  22. package/dist/esm/examples/MultiDeviceNode.js +18 -22
  23. package/dist/esm/examples/MultiDeviceNode.js.map +2 -2
  24. package/dist/esm/examples/MultiDeviceNodeLegacy.js +2 -1
  25. package/dist/esm/examples/MultiDeviceNodeLegacy.js.map +2 -2
  26. package/dist/esm/examples/SensorDeviceNode.js +17 -15
  27. package/dist/esm/examples/SensorDeviceNode.js.map +2 -2
  28. package/dist/esm/examples/cluster/DummyThreadNetworkCommissioningServer.js +1 -1
  29. package/dist/esm/examples/cluster/DummyThreadNetworkCommissioningServer.js.map +2 -2
  30. package/package.json +26 -10
  31. package/src/examples/{BridgedDeviceNode.ts → BridgedDevicesNode.ts} +23 -24
  32. package/src/examples/BridgedDevicesNodeLegacy.ts +9 -9
  33. package/src/examples/ComposedDeviceNode.ts +22 -23
  34. package/src/examples/ComposedDeviceNodeLegacy.ts +10 -10
  35. package/src/examples/ControllerNode.ts +32 -74
  36. package/src/examples/ControllerNodeLegacy.ts +2 -4
  37. package/src/examples/DeviceNode.ts +23 -24
  38. package/src/examples/DeviceNodeFull.ts +23 -24
  39. package/src/examples/DeviceNodeFullLegacy.ts +10 -11
  40. package/src/examples/LegacyStorageConverter.ts +156 -0
  41. package/src/examples/MultiDeviceNode.ts +21 -23
  42. package/src/examples/MultiDeviceNodeLegacy.ts +2 -4
  43. package/src/examples/SensorDeviceNode.ts +18 -15
  44. package/src/examples/cluster/DummyThreadNetworkCommissioningServer.ts +2 -2
  45. package/dist/esm/examples/BridgedDeviceNode.js.map +0 -7
@@ -20,8 +20,7 @@
20
20
  import "@project-chip/matter-node.js";
21
21
 
22
22
  import { BleNode } from "@project-chip/matter-node-ble.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";
23
+ import { requireMinNodeVersion } from "@project-chip/matter-node.js/util";
25
24
  import { CommissioningController, NodeCommissioningOptions } from "@project-chip/matter.js";
26
25
  import { Ble } from "@project-chip/matter.js/ble";
27
26
  import {
@@ -32,11 +31,10 @@ import {
32
31
  } from "@project-chip/matter.js/cluster";
33
32
  import { NodeId } from "@project-chip/matter.js/datatype";
34
33
  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";
34
+ import { Environment, StorageService } from "@project-chip/matter.js/environment";
35
+ import { Logger } from "@project-chip/matter.js/log";
37
36
  import { CommissioningOptions } from "@project-chip/matter.js/protocol";
38
37
  import { ManualPairingCodeCodec } from "@project-chip/matter.js/schema";
39
- import { StorageManager } from "@project-chip/matter.js/storage";
40
38
  import { Time } from "@project-chip/matter.js/time";
41
39
  import { singleton } from "@project-chip/matter.js/util";
42
40
 
@@ -44,64 +42,29 @@ const logger = Logger.get("Controller");
44
42
 
45
43
  requireMinNodeVersion(16);
46
44
 
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
- }
45
+ const environment = Environment.default;
73
46
 
74
- if (hasParameter("ble")) {
47
+ if (environment.vars.get("ble")) {
75
48
  // Initialize Ble
76
49
  Ble.get = singleton(
77
50
  () =>
78
51
  new BleNode({
79
- hciId: getIntParameter("ble-hci-id"),
52
+ hciId: environment.vars.number("ble-hci-id"),
80
53
  }),
81
54
  );
82
55
  }
83
56
 
84
- const storageLocation = getParameter("store") ?? ".controller-node";
85
- const storage = new StorageBackendDisk(storageLocation, hasParameter("clearstorage"));
86
- logger.info(`Storage location: ${storageLocation} (Directory)`);
57
+ const storageService = environment.get(StorageService);
58
+
59
+ console.log(`Storage location: ${storageService.location} (Directory)`);
87
60
  logger.info(
88
- 'Use the parameter "-store NAME" to specify a different storage location, use -clearstorage to start with an empty storage.',
61
+ 'Use the parameter "--storage-path=NAME-OR-PATH" to specify a different storage location in this directory, use --storage-clear to start with an empty storage.',
89
62
  );
90
63
 
91
64
  class ControllerNode {
92
65
  async start() {
93
66
  logger.info(`node-matter Controller started`);
94
67
 
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
68
  /**
106
69
  * Collect all needed data
107
70
  *
@@ -113,15 +76,19 @@ class ControllerNode {
113
76
  * (so maybe better not ;-)).
114
77
  */
115
78
 
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
- const uniqueId = controllerStorage.has("uniqueid")
120
- ? controllerStorage.get<string>("uniqueid")
121
- : getParameter("uniqueid") ?? Time.nowMs().toString();
122
- controllerStorage.set("uniqueid", uniqueId);
123
-
124
- const pairingCode = getParameter("pairingcode");
79
+ const controllerStorage = (await storageService.open("controller")).createContext("data");
80
+ const ip = (await controllerStorage.has("ip"))
81
+ ? controllerStorage.get<string>("ip")
82
+ : environment.vars.string("ip");
83
+ const port = (await controllerStorage.has("port"))
84
+ ? controllerStorage.get<number>("port")
85
+ : environment.vars.number("port");
86
+ const uniqueId = (await controllerStorage.has("uniqueid"))
87
+ ? await controllerStorage.get<string>("uniqueid")
88
+ : environment.vars.string("uniqueid") ?? Time.nowMs().toString();
89
+ await controllerStorage.set("uniqueid", uniqueId);
90
+
91
+ const pairingCode = environment.vars.string("pairingcode");
125
92
  let longDiscriminator, setupPin, shortDiscriminator;
126
93
  if (pairingCode !== undefined) {
127
94
  const pairingCodeCodec = ManualPairingCodeCodec.decode(pairingCode);
@@ -131,9 +98,10 @@ class ControllerNode {
131
98
  logger.debug(`Data extracted from pairing code: ${Logger.toJSON(pairingCodeCodec)}`);
132
99
  } else {
133
100
  longDiscriminator =
134
- getIntParameter("longDiscriminator") ?? controllerStorage.get("longDiscriminator", 3840);
101
+ environment.vars.number("longDiscriminator") ??
102
+ (await controllerStorage.get("longDiscriminator", 3840));
135
103
  if (longDiscriminator > 4095) throw new Error("Discriminator value must be less than 4096");
136
- setupPin = getIntParameter("pin") ?? controllerStorage.get("pin", 20202021);
104
+ setupPin = environment.vars.number("pin") ?? (await controllerStorage.get("pin", 20202021));
137
105
  }
138
106
  if ((shortDiscriminator === undefined && longDiscriminator === undefined) || setupPin === undefined) {
139
107
  throw new Error(
@@ -148,12 +116,12 @@ class ControllerNode {
148
116
  };
149
117
 
150
118
  let ble = false;
151
- if (hasParameter("ble")) {
119
+ if (environment.vars.get("ble")) {
152
120
  ble = true;
153
- const wifiSsid = getParameter("ble-wifi-ssid");
154
- const wifiCredentials = getParameter("ble-wifi-credentials");
155
- const threadNetworkName = getParameter("ble-thread-networkname");
156
- const threadOperationalDataset = getParameter("ble-thread-operationaldataset");
121
+ const wifiSsid = environment.vars.string("ble-wifi-ssid");
122
+ const wifiCredentials = environment.vars.string("ble-wifi-credentials");
123
+ const threadNetworkName = environment.vars.string("ble-thread-networkname");
124
+ const threadOperationalDataset = environment.vars.string("ble-thread-operationaldataset");
157
125
  if (wifiSsid !== undefined && wifiCredentials !== undefined) {
158
126
  logger.info(`Registering Commissioning over BLE with WiFi: ${wifiSsid}`);
159
127
  commissioningOptions.wifiNetwork = {
@@ -183,7 +151,6 @@ class ControllerNode {
183
151
  * are called.
184
152
  */
185
153
 
186
- const environment = Environment.default;
187
154
  const commissioningController = new CommissioningController({
188
155
  environment: {
189
156
  environment,
@@ -230,7 +197,7 @@ class ControllerNode {
230
197
  const nodes = commissioningController.getCommissionedNodes();
231
198
  console.log("Found commissioned nodes:", Logger.toJSON(nodes));
232
199
 
233
- const nodeId = NodeId(getIntParameter("nodeid") ?? nodes[0]);
200
+ const nodeId = NodeId(environment.vars.number("nodeid") ?? nodes[0]);
234
201
  if (!nodes.includes(nodeId)) {
235
202
  throw new Error(`Node ${nodeId} not found in commissioned nodes`);
236
203
  }
@@ -349,12 +316,3 @@ class ControllerNode {
349
316
  }
350
317
 
351
318
  new ControllerNode().start().catch(error => logger.error(error));
352
-
353
- process.on("SIGINT", () => {
354
- // Clean up on CTRL-C
355
- // Pragmatic way to make sure the storage is correctly closed before the process ends.
356
- storage
357
- .close()
358
- .then(() => process.exit(0))
359
- .catch(() => process.exit(1));
360
- });
@@ -347,8 +347,6 @@ new ControllerNode().start().catch(error => logger.error(error));
347
347
  process.on("SIGINT", () => {
348
348
  // Clean up on CTRL-C
349
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));
350
+ storage.close();
351
+ process.exit(0);
354
352
  });
@@ -96,20 +96,16 @@ async function main() {
96
96
  await server.add(endpoint);
97
97
 
98
98
  /**
99
- * Register state change handlers of the node for identify and onoff states to react to the commands.
99
+ * Register state change handlers and events of the node for identify and onoff states to react to the commands.
100
100
  * If the code in these change handlers fail then the change is also rolled back and not executed and an error is
101
101
  * reported back to the controller.
102
102
  */
103
- let isIdentifying = false;
104
- endpoint.events.identify.identifyTime$Change.on(value => {
105
- // identifyTime is set when an identify command is called and then decreased every second while indentify logic runs.
106
- if (value > 0 && !isIdentifying) {
107
- isIdentifying = true;
108
- console.log(`Run identify logic, ideally blink a light every 0.5s ...`);
109
- } else if (value === 0) {
110
- isIdentifying = false;
111
- console.log(`Stop identify logic ...`);
112
- }
103
+ endpoint.events.identify.startIdentifying.on(() => {
104
+ console.log(`Run identify logic, ideally blink a light every 0.5s ...`);
105
+ });
106
+
107
+ endpoint.events.identify.stopIdentifying.on(() => {
108
+ console.log(`Stop identify logic ...`);
113
109
  });
114
110
 
115
111
  endpoint.events.onOff.onOff$Change.on(value => {
@@ -162,30 +158,33 @@ async function getConfiguration() {
162
158
  );
163
159
  const deviceStorage = (await storageService.open("device")).createContext("data");
164
160
 
165
- const isSocket = deviceStorage.get("isSocket", environment.vars.get("type") === "socket");
166
- if (deviceStorage.has("isSocket")) {
161
+ const isSocket = await deviceStorage.get("isSocket", environment.vars.get("type") === "socket");
162
+ if (await deviceStorage.has("isSocket")) {
167
163
  console.log(`Device type ${isSocket ? "socket" : "light"} found in storage. --type parameter is ignored.`);
168
164
  }
169
165
  const deviceName = "Matter test device";
170
166
  const vendorName = "matter-node.js";
171
- const passcode = environment.vars.number("passcode") ?? deviceStorage.get("passcode", 20202021);
172
- const discriminator = environment.vars.number("discriminator") ?? deviceStorage.get("discriminator", 3840);
167
+ const passcode = environment.vars.number("passcode") ?? (await deviceStorage.get("passcode", 20202021));
168
+ const discriminator = environment.vars.number("discriminator") ?? (await deviceStorage.get("discriminator", 3840));
173
169
  // product name / id and vendor id should match what is in the device certificate
174
- const vendorId = environment.vars.number("vendorid") ?? deviceStorage.get("vendorid", 0xfff1);
170
+ const vendorId = environment.vars.number("vendorid") ?? (await deviceStorage.get("vendorid", 0xfff1));
175
171
  const productName = `node-matter OnOff ${isSocket ? "Socket" : "Light"}`;
176
- const productId = environment.vars.number("productid") ?? deviceStorage.get("productid", 0x8000);
172
+ const productId = environment.vars.number("productid") ?? (await deviceStorage.get("productid", 0x8000));
177
173
 
178
174
  const port = environment.vars.number("port") ?? 5540;
179
175
 
180
- const uniqueId = environment.vars.string("uniqueid") ?? deviceStorage.get("uniqueid", Time.nowMs().toString());
176
+ const uniqueId =
177
+ environment.vars.string("uniqueid") ?? (await deviceStorage.get("uniqueid", Time.nowMs())).toString();
181
178
 
182
179
  // Persist basic data to keep them also on restart
183
- deviceStorage.set("passcode", passcode);
184
- deviceStorage.set("discriminator", discriminator);
185
- deviceStorage.set("vendorid", vendorId);
186
- deviceStorage.set("productid", productId);
187
- deviceStorage.set("isSocket", isSocket);
188
- deviceStorage.set("uniqueid", uniqueId);
180
+ await deviceStorage.set({
181
+ passcode,
182
+ discriminator,
183
+ vendorid: vendorId,
184
+ productid: productId,
185
+ isSocket,
186
+ uniqueid: uniqueId,
187
+ });
189
188
 
190
189
  return {
191
190
  isSocket,
@@ -115,29 +115,31 @@ console.log(
115
115
 
116
116
  const deviceStorage = (await storageService.open("device")).createContext("data");
117
117
 
118
- if (deviceStorage.has("isSocket")) {
118
+ if (await deviceStorage.has("isSocket")) {
119
119
  console.log("Device type found in storage. --type parameter is ignored.");
120
120
  }
121
- const isSocket = deviceStorage.get("isSocket", environment.vars.string("type") === "socket");
121
+ const isSocket = await deviceStorage.get("isSocket", environment.vars.string("type") === "socket");
122
122
  const deviceName = "Matter test device";
123
123
  const vendorName = "matter-node.js";
124
- const passcode = environment.vars.number("passcode") ?? deviceStorage.get("passcode", 20202021);
125
- const discriminator = environment.vars.number("discriminator") ?? deviceStorage.get("discriminator", 3840);
124
+ const passcode = environment.vars.number("passcode") ?? (await deviceStorage.get("passcode", 20202021));
125
+ const discriminator = environment.vars.number("discriminator") ?? (await deviceStorage.get("discriminator", 3840));
126
126
  // product name / id and vendor id should match what is in the device certificate
127
- const vendorId = environment.vars.number("vendorid") ?? deviceStorage.get("vendorid", 0xfff1);
127
+ const vendorId = environment.vars.number("vendorid") ?? (await deviceStorage.get("vendorid", 0xfff1));
128
128
  const productName = `node-matter OnOff ${isSocket ? "Socket" : "Light"}`;
129
- const productId = environment.vars.number("productid") ?? deviceStorage.get("productid", 0x8000);
129
+ const productId = environment.vars.number("productid") ?? (await deviceStorage.get("productid", 0x8000));
130
130
 
131
131
  const port = environment.vars.number("port") ?? 5540;
132
132
 
133
- const uniqueId = environment.vars.string("uniqueid") ?? deviceStorage.get("uniqueid", Time.nowMs().toString());
133
+ const uniqueId = environment.vars.string("uniqueid") ?? (await deviceStorage.get("uniqueid", Time.nowMs().toString()));
134
134
 
135
- deviceStorage.set("passcode", passcode);
136
- deviceStorage.set("discriminator", discriminator);
137
- deviceStorage.set("vendorid", vendorId);
138
- deviceStorage.set("productid", productId);
139
- deviceStorage.set("isSocket", isSocket);
140
- deviceStorage.set("uniqueid", uniqueId);
135
+ await deviceStorage.set({
136
+ passcode,
137
+ discriminator,
138
+ vendorid: vendorId,
139
+ productid: productId,
140
+ isSocket,
141
+ uniqueid: uniqueId,
142
+ });
141
143
 
142
144
  // Matter exposes functionality in groups called "clusters". For this example device we override the matter.js "On/Off"
143
145
  // cluster implementation to print status to the console.
@@ -323,7 +325,7 @@ server.lifecycle.offline.on(() => console.log("Server is offline"));
323
325
  * This event is triggered when a fabric is added, removed or updated on the device. Use this if more granular
324
326
  * information is needed.
325
327
  */
326
- server.events.commissioning.commissionedFabricsChanged.on((fabricIndex, fabricAction) => {
328
+ server.events.commissioning.fabricsChanged.on((fabricIndex, fabricAction) => {
327
329
  let action = "";
328
330
  switch (fabricAction) {
329
331
  case FabricAction.Added:
@@ -337,7 +339,7 @@ server.events.commissioning.commissionedFabricsChanged.on((fabricIndex, fabricAc
337
339
  break;
338
340
  }
339
341
  console.log(`Commissioned Fabrics changed event (${action}) for ${fabricIndex} triggered`);
340
- console.log(server.state.operationalCredentials.fabrics);
342
+ console.log(server.state.commissioning.fabrics[fabricIndex]);
341
343
  });
342
344
 
343
345
  /**
@@ -358,15 +360,12 @@ server.events.sessions.subscriptionsChanged.on(session => {
358
360
  });
359
361
 
360
362
  // React on a change of identificationTime to do Identify stuff for the own device
361
- let isIdentifying = false;
362
- endpoint.events.identify.identifyTime$Change.on(value => {
363
- if (value > 0 && !isIdentifying) {
364
- isIdentifying = true;
365
- console.log(`Run identify logic, ideally blink a light every 0.5s ...`);
366
- } else if (value === 0) {
367
- isIdentifying = false;
368
- console.log(`Stop identify logic ...`);
369
- }
363
+ endpoint.events.identify.startIdentifying.on(() => {
364
+ console.log(`Run identify logic, ideally blink a light every 0.5s ...`);
365
+ });
366
+
367
+ endpoint.events.identify.stopIdentifying.on(() => {
368
+ console.log(`Stop identify logic ...`);
370
369
  });
371
370
 
372
371
  // Our device is now built and we can bring the node online.
@@ -134,13 +134,14 @@ class Device {
134
134
 
135
135
  const uniqueId = getIntParameter("uniqueid") ?? deviceStorage.get("uniqueid", Time.nowMs());
136
136
 
137
- deviceStorage.set("passcode", passcode);
138
- deviceStorage.set("discriminator", discriminator);
139
- deviceStorage.set("vendorid", vendorId);
140
- deviceStorage.set("productid", productId);
141
- deviceStorage.set("isSocket", isSocket);
142
- deviceStorage.set("uniqueid", uniqueId);
143
-
137
+ deviceStorage.set({
138
+ passcode,
139
+ discriminator,
140
+ vendorid: vendorId,
141
+ productid: productId,
142
+ isSocket,
143
+ uniqueid: uniqueId,
144
+ });
144
145
  /**
145
146
  * Create Device instance and add needed Listener
146
147
  *
@@ -298,10 +299,8 @@ process.on("SIGINT", () => {
298
299
  .stop()
299
300
  .then(() => {
300
301
  // Pragmatic way to make sure the storage is correctly closed before the process ends.
301
- storage
302
- .close()
303
- .then(() => process.exit(0))
304
- .catch(err => console.error(err));
302
+ storage.close();
303
+ process.exit(0);
305
304
  })
306
305
  .catch(err => console.error(err));
307
306
  });
@@ -0,0 +1,156 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2022-2024 Matter.js Authors
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ import "@project-chip/matter-node.js";
8
+ import { StorageBackendDisk } from "@project-chip/matter-node.js/storage";
9
+ import { Environment, StorageService } from "@project-chip/matter.js/environment";
10
+ import { Time } from "@project-chip/matter.js/time";
11
+ import { LocalStorage } from "node-localstorage";
12
+
13
+ const environment = Environment.default;
14
+
15
+ const legacyStoragePath = environment.vars.string("legacy.storage.path");
16
+ const newStoragePath = environment.vars.string("storage.path");
17
+
18
+ if (!legacyStoragePath || !newStoragePath) {
19
+ console.error("Usage: node LegacyStorageConverter.js --legacy-storage-path=<path> --storage-path=<path>");
20
+ process.exit(1);
21
+ }
22
+
23
+ const legacyLocalStorage = new LocalStorage(legacyStoragePath);
24
+
25
+ const legacyNodes = new Array<string>();
26
+ Object.keys(legacyLocalStorage).forEach(key => {
27
+ const firstLevel = key.split(".")[0];
28
+ if (!legacyNodes.includes(firstLevel)) {
29
+ legacyNodes.push(firstLevel);
30
+ }
31
+ });
32
+
33
+ const storageService = environment.get(StorageService);
34
+
35
+ const legacyStorage = new StorageBackendDisk(legacyStoragePath);
36
+ legacyStorage.initialize();
37
+
38
+ const uniqueIds: Record<string, string> = {};
39
+ if (legacyNodes.includes("Device")) {
40
+ console.log("Example Device found ...");
41
+ legacyNodes.splice(legacyNodes.indexOf("Device"), 1);
42
+
43
+ const newDeviceStorage = (await storageService.open("device")).createContext("data");
44
+
45
+ for (const key of legacyStorage.keys(["Device"])) {
46
+ console.log("Migrate Device.", key);
47
+ const value = legacyStorage.get(["Device"], key);
48
+ await newDeviceStorage.set(key, value);
49
+ if (key === "uniqueid") {
50
+ uniqueIds["0"] = String(value);
51
+ await newDeviceStorage.set(key, String(value));
52
+ } else if (key.startsWith("uniqueid")) {
53
+ const id = parseInt(key.substring(8));
54
+ uniqueIds[id - 1] = String(value);
55
+ await newDeviceStorage.set(key, String(value));
56
+ }
57
+ }
58
+ }
59
+
60
+ if (legacyNodes.includes("Controller")) {
61
+ console.log("Example Controller found ...");
62
+ legacyNodes.splice(legacyNodes.indexOf("Controller"), 1);
63
+
64
+ const newControllerStorage = (await storageService.open("controller")).createContext("data");
65
+
66
+ for (const key of legacyStorage.keys(["Controller"])) {
67
+ console.log("Migrate Controller.", key);
68
+ const value = legacyStorage.get(["Controller"], key);
69
+ await newControllerStorage.set(key, value);
70
+ if (key === "uniqueid") {
71
+ uniqueIds["0"] = String(value);
72
+ await newControllerStorage.set(key, String(value));
73
+ }
74
+ }
75
+ }
76
+
77
+ console.log(uniqueIds);
78
+
79
+ if (!Object.keys(uniqueIds).length) {
80
+ console.error("No uniqueId(s) found in legacy storage. Can not convert the node storage.");
81
+ process.exit(1);
82
+ }
83
+
84
+ for (const nodeId of legacyNodes) {
85
+ if (!uniqueIds[nodeId]) {
86
+ const rootCertId = legacyStorage.get(["0", "RootCertificateManager"], "rootCertId");
87
+
88
+ if (nodeId !== "0" || rootCertId === undefined) {
89
+ console.error(`No uniqueId found for node ${nodeId}. Can not convert the node storage.`);
90
+ continue;
91
+ }
92
+
93
+ // Migrate the controller storage
94
+ const newControllerStorage = (await storageService.open("controller")).createContext("data");
95
+ const uniqueId = Time.nowMs().toString();
96
+ await newControllerStorage.set("uniqueid", uniqueId);
97
+
98
+ const newNodeStorage = await storageService.open(uniqueId);
99
+
100
+ const credentialsStorage = newNodeStorage.createContext("credentials");
101
+ await credentialsStorage.set("rootCertId", rootCertId);
102
+ await credentialsStorage.set(
103
+ "nextCertificateId",
104
+ legacyStorage.get(["0", "RootCertificateManager"], "nextCertificateId"),
105
+ );
106
+ await credentialsStorage.set(
107
+ "rootCertBytes",
108
+ legacyStorage.get(["0", "RootCertificateManager"], "rootCertBytes"),
109
+ );
110
+ await credentialsStorage.set(
111
+ "rootKeyIdentifier",
112
+ legacyStorage.get(["0", "RootCertificateManager"], "rootKeyIdentifier"),
113
+ );
114
+ await credentialsStorage.set("rootKeyPair", legacyStorage.get(["0", "RootCertificateManager"], "rootKeyPair"));
115
+ await credentialsStorage.set("fabric", legacyStorage.get(["0", "MatterController"], "fabric"));
116
+
117
+ const sessionsStorage = newNodeStorage.createContext("sessions");
118
+ await sessionsStorage.set(
119
+ "resumptionRecords",
120
+ legacyStorage.get([nodeId, "SessionManager"], "resumptionRecords"),
121
+ );
122
+
123
+ const nodesStorage = newNodeStorage.createContext("nodes");
124
+ await nodesStorage.set(
125
+ "resumptionRecords",
126
+ legacyStorage.get([nodeId, "MatterController"], "commissionedNodes"),
127
+ );
128
+
129
+ console.log(`Controller Node ${nodeId} with new unique id ${uniqueId} migrated successfully.`);
130
+ } else {
131
+ // Migrate the device storage
132
+ const newNodeStorage = await storageService.open(uniqueIds[nodeId]);
133
+
134
+ const nextEndpointNumber = legacyStorage.get<number>([nodeId, "EndpointStructure"], "nextEndpointId");
135
+ if (nextEndpointNumber !== undefined && nextEndpointNumber > 2) {
136
+ console.log(
137
+ "It seems you used a bridged or composed example before, please make sure to use all details (type, ids,...) in the parameters when starting the new example. When using a bridge and you had changed devices after pairing it could happen that the new example introduces new devices to the controller. If you are unsure unpair the old example and start fresh.",
138
+ );
139
+ }
140
+
141
+ const eventsStorage = newNodeStorage.createContext("events");
142
+ await eventsStorage.set("lastEventNumber", legacyStorage.get([nodeId, "EventHandler"], "lastEventNumber"));
143
+
144
+ const fabricsStorage = newNodeStorage.createContext("fabrics");
145
+ await fabricsStorage.set("fabrics", legacyStorage.get([nodeId, "FabricManager"], "fabrics"));
146
+ await fabricsStorage.set("nextFabricIndex", legacyStorage.get([nodeId, "FabricManager"], "nextFabricIndex"));
147
+
148
+ const sessionsStorage = newNodeStorage.createContext("sessions");
149
+ await sessionsStorage.set(
150
+ "resumptionRecords",
151
+ legacyStorage.get([nodeId, "SessionManager"], "resumptionRecords"),
152
+ );
153
+
154
+ console.log(`Device Node ${nodeId} with unique id ${uniqueIds[nodeId]} migrated successfully.`);
155
+ }
156
+ }
@@ -99,16 +99,12 @@ for (let idx = 1; idx < devices.length; idx++) {
99
99
  * If the code in these change handlers fail then the change is also rolled back and not executed and an error is
100
100
  * reported back to the controller.
101
101
  */
102
- let isIdentifying = false;
103
- endpoint.events.identify.identifyTime$Change.on(value => {
104
- // identifyTime is set when an identify commandf is called and then decreased every second while indenitfy logic runs.
105
- if (value > 0 && !isIdentifying) {
106
- isIdentifying = true;
107
- console.log(`Run identify logic, ideally blink a light every 0.5s ...`);
108
- } else if (value === 0) {
109
- isIdentifying = false;
110
- console.log(`Stop identify logic ...`);
111
- }
102
+ endpoint.events.identify.startIdentifying.on(() => {
103
+ console.log(`Run identify logic for device ${i}, ideally blink a light every 0.5s ...`);
104
+ });
105
+
106
+ endpoint.events.identify.stopIdentifying.on(() => {
107
+ console.log(`Stop identify logic for device ${i}...`);
112
108
  });
113
109
 
114
110
  endpoint.events.onOff.onOff$Change.on(value => {
@@ -163,34 +159,36 @@ async function getConfiguration() {
163
159
  const devices = [];
164
160
  const numDevices = environment.vars.number("num") ?? 2;
165
161
  for (let i = 1; i <= numDevices; i++) {
166
- const isSocket = deviceStorage.get(`isSocket${i}`, environment.vars.string(`type${i}`) === "socket");
167
- if (deviceStorage.has(`isSocket${i}`)) {
162
+ const isSocket = await deviceStorage.get(`isSocket${i}`, environment.vars.string(`type${i}`) === "socket");
163
+ if (await deviceStorage.has(`isSocket${i}`)) {
168
164
  console.log(`Device type ${isSocket ? "socket" : "light"} found in storage. --type parameter is ignored.`);
169
165
  }
170
166
  const deviceName = `Matter ${environment.vars.string(`type${i}`) ?? "light"} device ${i}`;
171
167
  const vendorName = "matter-node.js";
172
168
  const passcode =
173
- environment.vars.number(`passcode${i}`) ?? deviceStorage.get(`passcode${i}`, defaultPasscode++);
169
+ environment.vars.number(`passcode${i}`) ?? (await deviceStorage.get(`passcode${i}`, defaultPasscode++));
174
170
  const discriminator =
175
171
  environment.vars.number(`discriminator${i}`) ??
176
- deviceStorage.get(`discriminator${i}`, defaultDiscriminator++);
172
+ (await deviceStorage.get(`discriminator${i}`, defaultDiscriminator++));
177
173
  // product name / id and vendor id should match what is in the device certificate
178
- const vendorId = environment.vars.number(`vendorid${i}`) ?? deviceStorage.get(`vendorid${i}`, 0xfff1);
174
+ const vendorId = environment.vars.number(`vendorid${i}`) ?? (await deviceStorage.get(`vendorid${i}`, 0xfff1));
179
175
  const productName = `node-matter OnOff-Device ${i}`;
180
- const productId = environment.vars.number(`productid${i}`) ?? deviceStorage.get(`productid${i}`, 0x8000);
176
+ const productId =
177
+ environment.vars.number(`productid${i}`) ?? (await deviceStorage.get(`productid${i}`, 0x8000));
181
178
 
182
179
  const port = environment.vars.number(`port${i}`) ?? defaultPort++;
183
180
 
184
181
  const uniqueId =
185
- environment.vars.string(`uniqueid${i}`) ?? deviceStorage.get(`uniqueid${i}`, `${i}-${Time.nowMs()}`);
182
+ environment.vars.string(`uniqueid${i}`) ??
183
+ (await deviceStorage.get(`uniqueid${i}`, `${i}-${Time.nowMs()}`));
186
184
 
187
185
  // Persist basic data to keep them also on restart
188
- deviceStorage.set(`passcode${i}`, passcode);
189
- deviceStorage.set(`discriminator${i}`, discriminator);
190
- deviceStorage.set(`vendorid${i}`, vendorId);
191
- deviceStorage.set(`productid${i}`, productId);
192
- deviceStorage.set(`isSocket${i}`, isSocket);
193
- deviceStorage.set(`uniqueid${i}`, uniqueId);
186
+ await deviceStorage.set(`passcode${i}`, passcode);
187
+ await deviceStorage.set(`discriminator${i}`, discriminator);
188
+ await deviceStorage.set(`vendorid${i}`, vendorId);
189
+ await deviceStorage.set(`productid${i}`, productId);
190
+ await deviceStorage.set(`isSocket${i}`, isSocket);
191
+ await deviceStorage.set(`uniqueid${i}`, uniqueId);
194
192
 
195
193
  devices.push({
196
194
  isSocket,
@@ -258,10 +258,8 @@ process.on("SIGINT", () => {
258
258
  .stop()
259
259
  .then(() => {
260
260
  // Pragmatic way to make sure the storage is correctly closed before the process ends.
261
- storage
262
- .close()
263
- .then(() => process.exit(0))
264
- .catch(err => console.error(err));
261
+ storage.close();
262
+ process.exit(0);
265
263
  })
266
264
  .catch(err => console.error(err));
267
265
  });