@project-chip/matter-node.js-examples 0.8.0-alpha.1-20240308-033110a3 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- package/README.md +17 -0
- package/dist/esm/examples/{BridgedDeviceNode.js → BridgedDevicesNode.js} +16 -14
- package/dist/esm/examples/{BridgedDeviceNode.js.map → BridgedDevicesNode.js.map} +3 -3
- package/dist/esm/examples/BridgedDevicesNodeLegacy.js +9 -6
- package/dist/esm/examples/BridgedDevicesNodeLegacy.js.map +2 -2
- package/dist/esm/examples/ComposedDeviceNode.js +15 -13
- package/dist/esm/examples/ComposedDeviceNode.js.map +2 -2
- package/dist/esm/examples/ComposedDeviceNodeLegacy.js +10 -7
- package/dist/esm/examples/ComposedDeviceNodeLegacy.js.map +2 -2
- package/dist/esm/examples/ControllerNode.js +23 -56
- package/dist/esm/examples/ControllerNode.js.map +2 -2
- package/dist/esm/examples/ControllerNodeLegacy.js +2 -1
- package/dist/esm/examples/ControllerNodeLegacy.js.map +2 -2
- package/dist/esm/examples/DeviceNode.js +15 -13
- package/dist/esm/examples/DeviceNode.js.map +2 -2
- package/dist/esm/examples/DeviceNodeFull.js +17 -15
- package/dist/esm/examples/DeviceNodeFull.js.map +2 -2
- package/dist/esm/examples/DeviceNodeFullLegacy.js +10 -7
- package/dist/esm/examples/DeviceNodeFullLegacy.js.map +2 -2
- package/dist/esm/examples/LegacyStorageConverter.js +126 -0
- package/dist/esm/examples/LegacyStorageConverter.js.map +7 -0
- package/dist/esm/examples/MultiDeviceNode.js +13 -13
- package/dist/esm/examples/MultiDeviceNode.js.map +2 -2
- package/dist/esm/examples/MultiDeviceNodeLegacy.js +2 -1
- package/dist/esm/examples/MultiDeviceNodeLegacy.js.map +2 -2
- package/dist/esm/examples/SensorDeviceNode.js +17 -15
- package/dist/esm/examples/SensorDeviceNode.js.map +2 -2
- package/dist/esm/examples/cluster/DummyThreadNetworkCommissioningServer.js +1 -1
- package/dist/esm/examples/cluster/DummyThreadNetworkCommissioningServer.js.map +2 -2
- package/package.json +26 -10
- package/src/examples/{BridgedDeviceNode.ts → BridgedDevicesNode.ts} +16 -13
- package/src/examples/BridgedDevicesNodeLegacy.ts +9 -9
- package/src/examples/ComposedDeviceNode.ts +16 -13
- package/src/examples/ComposedDeviceNodeLegacy.ts +10 -10
- package/src/examples/ControllerNode.ts +32 -74
- package/src/examples/ControllerNodeLegacy.ts +2 -4
- package/src/examples/DeviceNode.ts +16 -13
- package/src/examples/DeviceNodeFull.ts +17 -15
- package/src/examples/DeviceNodeFullLegacy.ts +10 -11
- package/src/examples/LegacyStorageConverter.ts +156 -0
- package/src/examples/MultiDeviceNode.ts +15 -13
- package/src/examples/MultiDeviceNodeLegacy.ts +2 -4
- package/src/examples/SensorDeviceNode.ts +18 -15
- package/src/examples/cluster/DummyThreadNetworkCommissioningServer.ts +2 -2
@@ -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 {
|
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 {
|
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
|
-
|
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 (
|
47
|
+
if (environment.vars.get("ble")) {
|
75
48
|
// Initialize Ble
|
76
49
|
Ble.get = singleton(
|
77
50
|
() =>
|
78
51
|
new BleNode({
|
79
|
-
hciId:
|
52
|
+
hciId: environment.vars.number("ble-hci-id"),
|
80
53
|
}),
|
81
54
|
);
|
82
55
|
}
|
83
56
|
|
84
|
-
const
|
85
|
-
|
86
|
-
|
57
|
+
const storageService = environment.get(StorageService);
|
58
|
+
|
59
|
+
console.log(`Storage location: ${storageService.location} (Directory)`);
|
87
60
|
logger.info(
|
88
|
-
'Use the parameter "-
|
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 =
|
117
|
-
const ip =
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
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
|
-
|
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 =
|
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 (
|
119
|
+
if (environment.vars.get("ble")) {
|
152
120
|
ble = true;
|
153
|
-
const wifiSsid =
|
154
|
-
const wifiCredentials =
|
155
|
-
const threadNetworkName =
|
156
|
-
const threadOperationalDataset =
|
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(
|
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
|
-
|
352
|
-
.then(() => process.exit(0))
|
353
|
-
.catch(() => process.exit(1));
|
350
|
+
storage.close();
|
351
|
+
process.exit(0);
|
354
352
|
});
|
@@ -162,30 +162,33 @@ async function getConfiguration() {
|
|
162
162
|
);
|
163
163
|
const deviceStorage = (await storageService.open("device")).createContext("data");
|
164
164
|
|
165
|
-
const isSocket = deviceStorage.get("isSocket", environment.vars.get("type") === "socket");
|
166
|
-
if (deviceStorage.has("isSocket")) {
|
165
|
+
const isSocket = await deviceStorage.get("isSocket", environment.vars.get("type") === "socket");
|
166
|
+
if (await deviceStorage.has("isSocket")) {
|
167
167
|
console.log(`Device type ${isSocket ? "socket" : "light"} found in storage. --type parameter is ignored.`);
|
168
168
|
}
|
169
169
|
const deviceName = "Matter test device";
|
170
170
|
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);
|
171
|
+
const passcode = environment.vars.number("passcode") ?? (await deviceStorage.get("passcode", 20202021));
|
172
|
+
const discriminator = environment.vars.number("discriminator") ?? (await deviceStorage.get("discriminator", 3840));
|
173
173
|
// 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);
|
174
|
+
const vendorId = environment.vars.number("vendorid") ?? (await deviceStorage.get("vendorid", 0xfff1));
|
175
175
|
const productName = `node-matter OnOff ${isSocket ? "Socket" : "Light"}`;
|
176
|
-
const productId = environment.vars.number("productid") ?? deviceStorage.get("productid", 0x8000);
|
176
|
+
const productId = environment.vars.number("productid") ?? (await deviceStorage.get("productid", 0x8000));
|
177
177
|
|
178
178
|
const port = environment.vars.number("port") ?? 5540;
|
179
179
|
|
180
|
-
const uniqueId =
|
180
|
+
const uniqueId =
|
181
|
+
environment.vars.string("uniqueid") ?? (await deviceStorage.get("uniqueid", Time.nowMs())).toString();
|
181
182
|
|
182
183
|
// Persist basic data to keep them also on restart
|
183
|
-
deviceStorage.set(
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
184
|
+
await deviceStorage.set({
|
185
|
+
passcode,
|
186
|
+
discriminator,
|
187
|
+
vendorid: vendorId,
|
188
|
+
productid: productId,
|
189
|
+
isSocket,
|
190
|
+
uniqueid: uniqueId,
|
191
|
+
});
|
189
192
|
|
190
193
|
return {
|
191
194
|
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(
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
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.
|
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.
|
342
|
+
console.log(server.state.commissioning.fabrics[fabricIndex]);
|
341
343
|
});
|
342
344
|
|
343
345
|
/**
|
@@ -134,13 +134,14 @@ class Device {
|
|
134
134
|
|
135
135
|
const uniqueId = getIntParameter("uniqueid") ?? deviceStorage.get("uniqueid", Time.nowMs());
|
136
136
|
|
137
|
-
deviceStorage.set(
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
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
|
-
|
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
|
+
}
|
@@ -163,34 +163,36 @@ async function getConfiguration() {
|
|
163
163
|
const devices = [];
|
164
164
|
const numDevices = environment.vars.number("num") ?? 2;
|
165
165
|
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}`)) {
|
166
|
+
const isSocket = await deviceStorage.get(`isSocket${i}`, environment.vars.string(`type${i}`) === "socket");
|
167
|
+
if (await deviceStorage.has(`isSocket${i}`)) {
|
168
168
|
console.log(`Device type ${isSocket ? "socket" : "light"} found in storage. --type parameter is ignored.`);
|
169
169
|
}
|
170
170
|
const deviceName = `Matter ${environment.vars.string(`type${i}`) ?? "light"} device ${i}`;
|
171
171
|
const vendorName = "matter-node.js";
|
172
172
|
const passcode =
|
173
|
-
environment.vars.number(`passcode${i}`) ?? deviceStorage.get(`passcode${i}`, defaultPasscode++);
|
173
|
+
environment.vars.number(`passcode${i}`) ?? (await deviceStorage.get(`passcode${i}`, defaultPasscode++));
|
174
174
|
const discriminator =
|
175
175
|
environment.vars.number(`discriminator${i}`) ??
|
176
|
-
deviceStorage.get(`discriminator${i}`, defaultDiscriminator++);
|
176
|
+
(await deviceStorage.get(`discriminator${i}`, defaultDiscriminator++));
|
177
177
|
// 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);
|
178
|
+
const vendorId = environment.vars.number(`vendorid${i}`) ?? (await deviceStorage.get(`vendorid${i}`, 0xfff1));
|
179
179
|
const productName = `node-matter OnOff-Device ${i}`;
|
180
|
-
const productId =
|
180
|
+
const productId =
|
181
|
+
environment.vars.number(`productid${i}`) ?? (await deviceStorage.get(`productid${i}`, 0x8000));
|
181
182
|
|
182
183
|
const port = environment.vars.number(`port${i}`) ?? defaultPort++;
|
183
184
|
|
184
185
|
const uniqueId =
|
185
|
-
environment.vars.string(`uniqueid${i}`) ??
|
186
|
+
environment.vars.string(`uniqueid${i}`) ??
|
187
|
+
(await deviceStorage.get(`uniqueid${i}`, `${i}-${Time.nowMs()}`));
|
186
188
|
|
187
189
|
// 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);
|
190
|
+
await deviceStorage.set(`passcode${i}`, passcode);
|
191
|
+
await deviceStorage.set(`discriminator${i}`, discriminator);
|
192
|
+
await deviceStorage.set(`vendorid${i}`, vendorId);
|
193
|
+
await deviceStorage.set(`productid${i}`, productId);
|
194
|
+
await deviceStorage.set(`isSocket${i}`, isSocket);
|
195
|
+
await deviceStorage.set(`uniqueid${i}`, uniqueId);
|
194
196
|
|
195
197
|
devices.push({
|
196
198
|
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
|
-
|
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
|
});
|
@@ -186,13 +186,13 @@ async function getConfiguration() {
|
|
186
186
|
);
|
187
187
|
const deviceStorage = (await storageService.open("device")).createContext("data");
|
188
188
|
|
189
|
-
const isTemperature = deviceStorage.get("isTemperature", environment.vars.get("type") !== "humidity");
|
190
|
-
if (deviceStorage.has("isTemperature")) {
|
189
|
+
const isTemperature = await deviceStorage.get("isTemperature", environment.vars.get("type") !== "humidity");
|
190
|
+
if (await deviceStorage.has("isTemperature")) {
|
191
191
|
console.log(
|
192
192
|
`Device type ${isTemperature ? "temperature" : "humidity"} found in storage. --type parameter is ignored.`,
|
193
193
|
);
|
194
194
|
}
|
195
|
-
let interval = environment.vars.number("interval") ?? deviceStorage.get("interval", 60);
|
195
|
+
let interval = environment.vars.number("interval") ?? (await deviceStorage.get("interval", 60));
|
196
196
|
if (interval < 1) {
|
197
197
|
console.log(`Invalid Interval ${interval}, set to 60s`);
|
198
198
|
interval = 60;
|
@@ -200,25 +200,28 @@ async function getConfiguration() {
|
|
200
200
|
|
201
201
|
const deviceName = "Matter test device";
|
202
202
|
const vendorName = "matter-node.js";
|
203
|
-
const passcode = environment.vars.number("passcode") ?? deviceStorage.get("passcode", 20202021);
|
204
|
-
const discriminator = environment.vars.number("discriminator") ?? deviceStorage.get("discriminator", 3840);
|
203
|
+
const passcode = environment.vars.number("passcode") ?? (await deviceStorage.get("passcode", 20202021));
|
204
|
+
const discriminator = environment.vars.number("discriminator") ?? (await deviceStorage.get("discriminator", 3840));
|
205
205
|
// product name / id and vendor id should match what is in the device certificate
|
206
|
-
const vendorId = environment.vars.number("vendorid") ?? deviceStorage.get("vendorid", 0xfff1);
|
206
|
+
const vendorId = environment.vars.number("vendorid") ?? (await deviceStorage.get("vendorid", 0xfff1));
|
207
207
|
const productName = `node-matter OnOff ${isTemperature ? "Temperature" : "Humidity"}`;
|
208
|
-
const productId = environment.vars.number("productid") ?? deviceStorage.get("productid", 0x8000);
|
208
|
+
const productId = environment.vars.number("productid") ?? (await deviceStorage.get("productid", 0x8000));
|
209
209
|
|
210
210
|
const port = environment.vars.number("port") ?? 5540;
|
211
211
|
|
212
|
-
const uniqueId =
|
212
|
+
const uniqueId =
|
213
|
+
environment.vars.string("uniqueid") ?? (await deviceStorage.get("uniqueid", Time.nowMs().toString()));
|
213
214
|
|
214
215
|
// Persist basic data to keep them also on restart
|
215
|
-
deviceStorage.set(
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
216
|
+
await deviceStorage.set({
|
217
|
+
passcode,
|
218
|
+
discriminator,
|
219
|
+
vendorid: vendorId,
|
220
|
+
productid: productId,
|
221
|
+
interval,
|
222
|
+
isTemperature,
|
223
|
+
uniqueid: uniqueId,
|
224
|
+
});
|
222
225
|
|
223
226
|
return {
|
224
227
|
isTemperature,
|
@@ -21,7 +21,7 @@ import { ByteArray } from "@project-chip/matter.js/util";
|
|
21
21
|
const firstNetworkId = new ByteArray(32);
|
22
22
|
|
23
23
|
/**
|
24
|
-
* This represents a Dummy version of a
|
24
|
+
* This represents a Dummy version of a Thread Network Commissioning Cluster Server without real thread related logic, beside
|
25
25
|
* returning some values provided as CLI parameters. This dummy implementation is only there for tests/as showcase for BLE
|
26
26
|
* commissioning of a device.
|
27
27
|
*/
|
@@ -64,7 +64,7 @@ export class DummyThreadNetworkCommissioningServer extends NetworkCommissioningB
|
|
64
64
|
|
65
65
|
override addOrUpdateThreadNetwork({ operationalDataset, breadcrumb }: AddOrUpdateThreadNetworkRequest) {
|
66
66
|
console.log(
|
67
|
-
`--->
|
67
|
+
`---> addOrUpdateThreadNetwork called on NetworkCommissioning cluster: ${operationalDataset.toHex()} ${breadcrumb}`,
|
68
68
|
);
|
69
69
|
|
70
70
|
this.session.context.assertFailSafeArmed("Failsafe timer needs to be armed to add or update networks.");
|