@project-chip/matter.js 0.12.4-alpha.0-20250209-00d44975c → 0.12.4-alpha.0-20250210-ad8edf096

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -133,37 +133,41 @@ export type NodeCommissioningOptions = CommissioningControllerNodeOptions & {
133
133
 
134
134
  /** Controller class to commission and connect multiple nodes into one fabric. */
135
135
  export class CommissioningController extends MatterNode {
136
- private started = false;
137
- private ipv4Disabled?: boolean;
138
- private readonly listeningAddressIpv4?: string;
139
- private readonly listeningAddressIpv6?: string;
136
+ #started = false;
137
+ #ipv4Disabled?: boolean;
138
+ readonly #listeningAddressIpv4?: string;
139
+ readonly #listeningAddressIpv6?: string;
140
140
 
141
- private environment?: Environment; // Set when new API was initialized correctly
142
- private storage?: StorageContext;
141
+ readonly #options: CommissioningControllerOptions;
143
142
 
144
- private mdnsScanner?: MdnsScanner;
145
- private mdnsBroadcaster?: MdnsBroadcaster;
143
+ #environment?: Environment; // Set when new API was initialized correctly
144
+ #storage?: StorageContext;
146
145
 
147
- private controllerInstance?: MatterController;
148
- private initializedNodes = new Map<NodeId, PairedNode>();
149
- private nodeUpdateLabelHandlers = new Map<NodeId, (nodeState: NodeStates) => Promise<void>>();
150
- private sessionDisconnectedHandler = new Map<NodeId, () => Promise<void>>();
146
+ #mdnsScanner?: MdnsScanner;
147
+ #mdnsBroadcaster?: MdnsBroadcaster;
148
+
149
+ #controllerInstance?: MatterController;
150
+ readonly #initializedNodes = new Map<NodeId, PairedNode>();
151
+ readonly #nodeUpdateLabelHandlers = new Map<NodeId, (nodeState: NodeStates) => Promise<void>>();
152
+ readonly #sessionDisconnectedHandler = new Map<NodeId, () => Promise<void>>();
151
153
 
152
154
  /**
153
155
  * Creates a new CommissioningController instance
154
156
  *
155
157
  * @param options The options for the CommissioningController
156
158
  */
157
- constructor(private readonly options: CommissioningControllerOptions) {
159
+ constructor(options: CommissioningControllerOptions) {
158
160
  super();
161
+ this.#options = options;
159
162
  }
160
163
 
161
164
  get nodeId() {
162
- return this.controllerInstance?.nodeId;
165
+ return this.#controllerInstance?.nodeId;
163
166
  }
164
167
 
168
+ /** Returns the configuration data needed to create a PASE commissioner, e.g. in a mobile app. */
165
169
  get paseCommissionerConfig() {
166
- const controller = this.assertControllerIsStarted(
170
+ const controller = this.#assertControllerIsStarted(
167
171
  "The CommissioningController needs to be started to get the PASE commissioner data.",
168
172
  );
169
173
  const { caConfig, fabricConfig: fabricData } = controller;
@@ -173,33 +177,33 @@ export class CommissioningController extends MatterNode {
173
177
  };
174
178
  }
175
179
 
176
- assertIsAddedToMatterServer() {
177
- if (this.mdnsScanner === undefined || (this.storage === undefined && this.environment === undefined)) {
180
+ #assertIsAddedToMatterServer() {
181
+ if (this.#mdnsScanner === undefined || (this.#storage === undefined && this.#environment === undefined)) {
178
182
  throw new ImplementationError("Add the node to the Matter instance before.");
179
183
  }
180
- if (!this.started) {
184
+ if (!this.#started) {
181
185
  throw new ImplementationError("The node needs to be started before interacting with the controller.");
182
186
  }
183
- return { mdnsScanner: this.mdnsScanner, storage: this.storage, environment: this.environment };
187
+ return { mdnsScanner: this.#mdnsScanner, storage: this.#storage, environment: this.#environment };
184
188
  }
185
189
 
186
- assertControllerIsStarted(errorText?: string) {
187
- if (this.controllerInstance === undefined) {
190
+ #assertControllerIsStarted(errorText?: string) {
191
+ if (this.#controllerInstance === undefined) {
188
192
  throw new ImplementationError(
189
193
  errorText ?? "Controller instance not yet started. Please call start() first.",
190
194
  );
191
195
  }
192
- return this.controllerInstance;
196
+ return this.#controllerInstance;
193
197
  }
194
198
 
195
199
  /** Internal method to initialize a MatterController instance. */
196
- private async initializeController() {
197
- const { mdnsScanner, storage, environment } = this.assertIsAddedToMatterServer();
198
- if (this.controllerInstance !== undefined) {
199
- return this.controllerInstance;
200
+ async #initializeController() {
201
+ const { mdnsScanner, storage, environment } = this.#assertIsAddedToMatterServer();
202
+ if (this.#controllerInstance !== undefined) {
203
+ return this.#controllerInstance;
200
204
  }
201
205
  const { localPort, adminFabricId, adminVendorId, adminFabricIndex, caseAuthenticatedTags, adminFabricLabel } =
202
- this.options;
206
+ this.#options;
203
207
 
204
208
  if (environment === undefined && storage === undefined) {
205
209
  throw new ImplementationError("Storage not initialized correctly.");
@@ -211,11 +215,11 @@ export class CommissioningController extends MatterNode {
211
215
  : new LegacyControllerStore(storage!);
212
216
 
213
217
  const { netInterfaces, scanners, port } = await configureNetwork({
214
- ipv4Disabled: this.ipv4Disabled,
218
+ ipv4Disabled: this.#ipv4Disabled,
215
219
  mdnsScanner,
216
220
  localPort,
217
- listeningAddressIpv4: this.listeningAddressIpv4,
218
- listeningAddressIpv6: this.listeningAddressIpv6,
221
+ listeningAddressIpv4: this.#listeningAddressIpv4,
222
+ listeningAddressIpv6: this.#listeningAddressIpv6,
219
223
  });
220
224
 
221
225
  const controller = await MatterController.create({
@@ -224,7 +228,7 @@ export class CommissioningController extends MatterNode {
224
228
  netInterfaces,
225
229
  sessionClosedCallback: peerNodeId => {
226
230
  logger.info(`Session for peer node ${peerNodeId} disconnected ...`);
227
- const handler = this.sessionDisconnectedHandler.get(peerNodeId);
231
+ const handler = this.#sessionDisconnectedHandler.get(peerNodeId);
228
232
  if (handler !== undefined) {
229
233
  handler().catch(error => logger.warn(`Error while handling session disconnect: ${error}`));
230
234
  }
@@ -235,30 +239,30 @@ export class CommissioningController extends MatterNode {
235
239
  caseAuthenticatedTags,
236
240
  adminFabricLabel,
237
241
  });
238
- if (this.mdnsBroadcaster) {
239
- controller.addBroadcaster(this.mdnsBroadcaster.createInstanceBroadcaster(port));
242
+ if (this.#mdnsBroadcaster) {
243
+ controller.addBroadcaster(this.#mdnsBroadcaster.createInstanceBroadcaster(port));
240
244
  }
241
245
  return controller;
242
246
  }
243
247
 
244
248
  /**
245
249
  * Commissions/Pairs a new device into the controller fabric. The method returns the NodeId of the commissioned
246
- * node.
250
+ * node on success.
247
251
  */
248
252
  async commissionNode(nodeOptions: NodeCommissioningOptions, connectNodeAfterCommissioning = true) {
249
- this.assertIsAddedToMatterServer();
250
- const controller = this.assertControllerIsStarted();
253
+ this.#assertIsAddedToMatterServer();
254
+ const controller = this.#assertControllerIsStarted();
251
255
 
252
256
  const nodeId = await controller.commission(nodeOptions);
253
257
 
254
258
  if (connectNodeAfterCommissioning) {
255
259
  const node = await this.connectNode(nodeId, {
256
260
  ...nodeOptions,
257
- autoSubscribe: nodeOptions.autoSubscribe ?? this.options.autoSubscribe,
261
+ autoSubscribe: nodeOptions.autoSubscribe ?? this.#options.autoSubscribe,
258
262
  subscribeMinIntervalFloorSeconds:
259
- nodeOptions.subscribeMinIntervalFloorSeconds ?? this.options.subscribeMinIntervalFloorSeconds,
263
+ nodeOptions.subscribeMinIntervalFloorSeconds ?? this.#options.subscribeMinIntervalFloorSeconds,
260
264
  subscribeMaxIntervalCeilingSeconds:
261
- nodeOptions.subscribeMaxIntervalCeilingSeconds ?? this.options.subscribeMaxIntervalCeilingSeconds,
265
+ nodeOptions.subscribeMaxIntervalCeilingSeconds ?? this.#options.subscribeMaxIntervalCeilingSeconds,
262
266
  });
263
267
  await node.events.initialized;
264
268
  }
@@ -272,14 +276,14 @@ export class CommissioningController extends MatterNode {
272
276
  * process.
273
277
  */
274
278
  completeCommissioningForNode(peerNodeId: NodeId, discoveryData?: DiscoveryData) {
275
- this.assertIsAddedToMatterServer();
276
- const controller = this.assertControllerIsStarted();
279
+ this.#assertIsAddedToMatterServer();
280
+ const controller = this.#assertControllerIsStarted();
277
281
  return controller.completeCommissioning(peerNodeId, discoveryData);
278
282
  }
279
283
 
280
284
  /** Check if a given node id is commissioned on this controller. */
281
285
  isNodeCommissioned(nodeId: NodeId) {
282
- const controller = this.assertControllerIsStarted();
286
+ const controller = this.#assertControllerIsStarted();
283
287
  return controller.getCommissionedNodes().includes(nodeId) ?? false;
284
288
  }
285
289
 
@@ -287,11 +291,13 @@ export class CommissioningController extends MatterNode {
287
291
  * Remove a Node id from the controller. This method should only be used if the decommission method on the
288
292
  * PairedNode instance returns an error. By default, it tries to decommission the node from the controller but will
289
293
  * remove it also in case of an error during decommissioning. Ideally try to decommission the node before and only
290
- * use this in case of an error.
294
+ * use this in case of an error as last option.
295
+ * If this method is used the state of the PairedNode instance might be out of sync, so the PairedNode instance
296
+ * should be disconnected first.
291
297
  */
292
298
  async removeNode(nodeId: NodeId, tryDecommissioning = true) {
293
- const controller = this.assertControllerIsStarted();
294
- const node = this.initializedNodes.get(nodeId);
299
+ const controller = this.#assertControllerIsStarted();
300
+ const node = this.#initializedNodes.get(nodeId);
295
301
  let decommissionSuccess = false;
296
302
  if (tryDecommissioning) {
297
303
  try {
@@ -308,19 +314,24 @@ export class CommissioningController extends MatterNode {
308
314
  node.close(!decommissionSuccess);
309
315
  }
310
316
  await controller.removeNode(nodeId);
311
- this.initializedNodes.delete(nodeId);
317
+ this.#initializedNodes.delete(nodeId);
312
318
  }
313
319
 
320
+ /** @deprecated Use PairedNode.disconnect() instead */
314
321
  async disconnectNode(nodeId: NodeId) {
315
- const node = this.initializedNodes.get(nodeId);
322
+ const node = this.#initializedNodes.get(nodeId);
316
323
  if (node === undefined) {
317
324
  throw new ImplementationError(`Node ${nodeId} is not connected!`);
318
325
  }
319
- await this.controllerInstance?.disconnect(nodeId);
326
+ await this.#controllerInstance?.disconnect(nodeId);
320
327
  }
321
328
 
329
+ /**
330
+ * Returns the PairedNode instance for a given NodeId. The instance is initialized without auto connect if not yet
331
+ * created.
332
+ */
322
333
  async getNode(nodeId: NodeId) {
323
- const existingNode = this.initializedNodes.get(nodeId);
334
+ const existingNode = this.#initializedNodes.get(nodeId);
324
335
  if (existingNode !== undefined) {
325
336
  return existingNode;
326
337
  }
@@ -332,15 +343,17 @@ export class CommissioningController extends MatterNode {
332
343
  * After connection the endpoint data of the device is analyzed and an object structure is created.
333
344
  * This call is not blocking and returns an initialized PairedNode instance. The connection or reconnection
334
345
  * happens in the background. Please monitor the state of the node to see if the connection was successful.
346
+ *
347
+ * @deprecated Use getNode() instead and call PairedNode.connect() or PairedNode.disconnect() as needed.
335
348
  */
336
349
  async connectNode(nodeId: NodeId, connectOptions?: CommissioningControllerNodeOptions) {
337
- const controller = this.assertControllerIsStarted();
350
+ const controller = this.#assertControllerIsStarted();
338
351
 
339
352
  if (!controller.getCommissionedNodes().includes(nodeId)) {
340
353
  throw new ImplementationError(`Node ${nodeId} is not commissioned!`);
341
354
  }
342
355
 
343
- const existingNode = this.initializedNodes.get(nodeId);
356
+ const existingNode = this.#initializedNodes.get(nodeId);
344
357
  if (existingNode !== undefined) {
345
358
  if (!existingNode.initialized) {
346
359
  existingNode.connect(connectOptions);
@@ -352,14 +365,14 @@ export class CommissioningController extends MatterNode {
352
365
  nodeId,
353
366
  this,
354
367
  connectOptions,
355
- this.controllerInstance?.getCommissionedNodeDetails(nodeId)?.deviceData ?? {},
368
+ this.#controllerInstance?.getCommissionedNodeDetails(nodeId)?.deviceData ?? {},
356
369
  await this.createInteractionClient(nodeId, NodeDiscoveryType.None, false), // First connect without discovery to last known address
357
370
  async (discoveryType?: NodeDiscoveryType) => void (await controller.connect(nodeId, { discoveryType })),
358
- handler => this.sessionDisconnectedHandler.set(nodeId, handler),
371
+ handler => this.#sessionDisconnectedHandler.set(nodeId, handler),
359
372
  controller.sessions,
360
- await this.collectStoredAttributeData(nodeId),
373
+ await this.#collectStoredAttributeData(nodeId),
361
374
  );
362
- this.initializedNodes.set(nodeId, pairedNode);
375
+ this.#initializedNodes.set(nodeId, pairedNode);
363
376
 
364
377
  pairedNode.events.initializedFromRemote.on(
365
378
  async deviceData => await controller.enhanceCommissionedNodeDetails(nodeId, deviceData),
@@ -368,8 +381,8 @@ export class CommissioningController extends MatterNode {
368
381
  return pairedNode;
369
382
  }
370
383
 
371
- async collectStoredAttributeData(nodeId: NodeId): Promise<DecodedAttributeReportValue<any>[]> {
372
- const controller = this.assertControllerIsStarted();
384
+ async #collectStoredAttributeData(nodeId: NodeId): Promise<DecodedAttributeReportValue<any>[]> {
385
+ const controller = this.#assertControllerIsStarted();
373
386
  const storedDataVersions = await controller.getStoredClusterDataVersions(nodeId);
374
387
  const result = new Array<DecodedAttributeReportValue<any>>();
375
388
  for (const { endpointId, clusterId } of storedDataVersions) {
@@ -381,9 +394,11 @@ export class CommissioningController extends MatterNode {
381
394
  /**
382
395
  * Connects to all paired nodes.
383
396
  * After connection the endpoint data of the device is analyzed and an object structure is created.
397
+ *
398
+ * @deprecated Use getCommissionedNodes() to get the list of nodes and getNode(nodeId) instead and call PairedNode.connect() or PairedNode.disconnect() as needed.
384
399
  */
385
400
  async connect(connectOptions?: CommissioningControllerNodeOptions) {
386
- const controller = this.assertControllerIsStarted();
401
+ const controller = this.#assertControllerIsStarted();
387
402
 
388
403
  if (!controller.isCommissioned()) {
389
404
  throw new ImplementationError(
@@ -394,40 +409,43 @@ export class CommissioningController extends MatterNode {
394
409
  for (const nodeId of controller.getCommissionedNodes()) {
395
410
  await this.connectNode(nodeId, connectOptions);
396
411
  }
397
- return Array.from(this.initializedNodes.values());
412
+ return Array.from(this.#initializedNodes.values());
398
413
  }
399
414
 
400
415
  /**
401
416
  * Set the MDNS Scanner instance. Should be only used internally
402
417
  *
403
418
  * @param mdnsScanner MdnsScanner instance
419
+ * @private
404
420
  */
405
421
  setMdnsScanner(mdnsScanner: MdnsScanner) {
406
- this.mdnsScanner = mdnsScanner;
422
+ this.#mdnsScanner = mdnsScanner;
407
423
  }
408
424
 
409
425
  /**
410
426
  * Set the MDNS Broadcaster instance. Should be only used internally
411
427
  *
412
428
  * @param mdnsBroadcaster MdnsBroadcaster instance
429
+ * @private
413
430
  */
414
431
  setMdnsBroadcaster(mdnsBroadcaster: MdnsBroadcaster) {
415
- this.mdnsBroadcaster = mdnsBroadcaster;
432
+ this.#mdnsBroadcaster = mdnsBroadcaster;
416
433
  }
417
434
 
418
435
  /**
419
436
  * Set the Storage instance. Should be only used internally
420
437
  *
421
438
  * @param storage storage context to use
439
+ * @private
422
440
  */
423
441
  setStorage(storage: StorageContext<SyncStorage>) {
424
- this.storage = storage;
425
- this.environment = undefined;
442
+ this.#storage = storage;
443
+ this.#environment = undefined;
426
444
  }
427
445
 
428
446
  /** Returns true if t least one node is commissioned/paired with this controller instance. */
429
447
  isCommissioned() {
430
- const controller = this.assertControllerIsStarted();
448
+ const controller = this.#assertControllerIsStarted();
431
449
 
432
450
  return controller.isCommissioned();
433
451
  }
@@ -441,78 +459,90 @@ export class CommissioningController extends MatterNode {
441
459
  discoveryType?: NodeDiscoveryType,
442
460
  forcedConnection = true,
443
461
  ): Promise<InteractionClient> {
444
- const controller = this.assertControllerIsStarted();
462
+ const controller = this.#assertControllerIsStarted();
445
463
  if (!forcedConnection) {
446
464
  return controller.createInteractionClient(nodeId, { discoveryType });
447
465
  }
448
466
  return controller.connect(nodeId, { discoveryType });
449
467
  }
450
468
 
451
- /** Returns the PairedNode instance for a given node id, if this node is connected. */
469
+ /**
470
+ * Returns the PairedNode instance for a given node id, if this node is connected.
471
+ * @deprecated Use getNode() instead
472
+ */
452
473
  getPairedNode(nodeId: NodeId) {
453
- return this.initializedNodes.get(nodeId);
474
+ return this.#initializedNodes.get(nodeId);
454
475
  }
455
476
 
456
- /** Returns an array with the Node Ids for all commissioned nodes. */
477
+ /** Returns an array with the NodeIds of all commissioned nodes. */
457
478
  getCommissionedNodes() {
458
- const controller = this.assertControllerIsStarted();
479
+ const controller = this.#assertControllerIsStarted();
459
480
 
460
481
  return controller.getCommissionedNodes() ?? [];
461
482
  }
462
483
 
484
+ /** Returns an arra with all commissioned NodeIds and their metadata. */
463
485
  getCommissionedNodesDetails() {
464
- const controller = this.assertControllerIsStarted();
486
+ const controller = this.#assertControllerIsStarted();
465
487
 
466
488
  return controller.getCommissionedNodesDetails() ?? [];
467
489
  }
468
490
 
469
- /** Disconnects all connected nodes and Closes the network connections and other resources of the controller. */
491
+ /**
492
+ * Disconnects all connected nodes and closes the network connections and other resources of the controller.
493
+ * You can use "start()" to restart the controller after closing it.
494
+ */
470
495
  async close() {
471
- for (const node of this.initializedNodes.values()) {
496
+ for (const node of this.#initializedNodes.values()) {
472
497
  node.close();
473
498
  }
474
- await this.controllerInstance?.close();
475
- this.controllerInstance = undefined;
476
- this.initializedNodes.clear();
477
- this.ipv4Disabled = undefined;
478
- this.started = false;
499
+ await this.#controllerInstance?.close();
500
+ this.#controllerInstance = undefined;
501
+ this.#initializedNodes.clear();
502
+ this.#ipv4Disabled = undefined;
503
+ this.#started = false;
479
504
  }
480
505
 
506
+ /** Return the port used by the controller for the UDP interface. */
481
507
  getPort(): number | undefined {
482
- return this.options.localPort;
508
+ return this.#options.localPort;
483
509
  }
484
510
 
511
+ /** @private */
485
512
  initialize(ipv4Disabled: boolean) {
486
- if (this.started) {
513
+ if (this.#started) {
487
514
  throw new ImplementationError("Controller instance already started.");
488
515
  }
489
- if (this.ipv4Disabled !== undefined && this.ipv4Disabled !== ipv4Disabled) {
516
+ if (this.#ipv4Disabled !== undefined && this.#ipv4Disabled !== ipv4Disabled) {
490
517
  throw new ImplementationError(
491
518
  "Changing the IPv4 disabled flag after starting the controller is not supported.",
492
519
  );
493
520
  }
494
- this.ipv4Disabled = ipv4Disabled;
521
+ this.#ipv4Disabled = ipv4Disabled;
495
522
  }
496
523
 
524
+ /** @private */
497
525
  async initializeControllerStore() {
498
526
  // This can only happen if "MatterServer" approach is not used
499
- if (this.options.environment === undefined) {
527
+ if (this.#options.environment === undefined) {
500
528
  throw new ImplementationError("Initialization not done. Add the controller to the MatterServer first.");
501
529
  }
502
530
 
503
- const { environment, id } = this.options.environment;
531
+ const { environment, id } = this.#options.environment;
504
532
  const controllerStore = await ControllerStore.create(id, environment);
505
533
  environment.set(ControllerStore, controllerStore);
506
534
  }
507
535
 
508
- /** Initialize the controller and connect to all commissioned nodes if autoConnect is not set to false. */
536
+ /**
537
+ * Initialize the controller and initialize and connect to all commissioned nodes if autoConnect is not set to false.
538
+ */
509
539
  async start() {
510
- if (this.ipv4Disabled === undefined) {
511
- if (this.options.environment === undefined) {
540
+ if (this.#ipv4Disabled === undefined) {
541
+ if (this.#options.environment === undefined) {
512
542
  throw new ImplementationError("Initialization not done. Add the controller to the MatterServer first.");
513
543
  }
514
544
 
515
- const { environment } = this.options.environment;
545
+ const { environment } = this.#options.environment;
516
546
 
517
547
  if (!environment.has(ControllerStore)) {
518
548
  await this.initializeControllerStore();
@@ -520,44 +550,52 @@ export class CommissioningController extends MatterNode {
520
550
 
521
551
  // Load the MDNS service from the environment and set onto the controller
522
552
  const mdnsService = await environment.load(MdnsService);
523
- this.ipv4Disabled = !mdnsService.enableIpv4;
553
+ this.#ipv4Disabled = !mdnsService.enableIpv4;
524
554
  this.setMdnsBroadcaster(mdnsService.broadcaster);
525
555
  this.setMdnsScanner(mdnsService.scanner);
526
556
 
527
- this.environment = environment;
528
- const runtime = this.environment.runtime;
557
+ this.#environment = environment;
558
+ const runtime = this.#environment.runtime;
529
559
  runtime.add(this);
530
560
  }
531
561
 
532
- this.started = true;
533
- if (this.controllerInstance === undefined) {
534
- this.controllerInstance = await this.initializeController();
562
+ this.#started = true;
563
+ if (this.#controllerInstance === undefined) {
564
+ this.#controllerInstance = await this.#initializeController();
535
565
  }
536
- await this.controllerInstance.announce();
537
- if (this.options.autoConnect !== false && this.controllerInstance.isCommissioned()) {
566
+ await this.#controllerInstance.announce();
567
+ if (this.#options.autoConnect !== false && this.#controllerInstance.isCommissioned()) {
538
568
  await this.connect();
539
569
  }
540
570
  }
541
571
 
572
+ /**
573
+ * Cancels the discovery process for commissionable devices started with discoverCommissionableDevices().
574
+ */
542
575
  cancelCommissionableDeviceDiscovery(
543
576
  identifierData: CommissionableDeviceIdentifiers,
544
577
  discoveryCapabilities?: TypeFromPartialBitSchema<typeof DiscoveryCapabilitiesBitmap>,
545
578
  ) {
546
- this.assertIsAddedToMatterServer();
547
- const controller = this.assertControllerIsStarted();
579
+ this.#assertIsAddedToMatterServer();
580
+ const controller = this.#assertControllerIsStarted();
548
581
  controller
549
582
  .collectScanners(discoveryCapabilities)
550
583
  .forEach(scanner => ControllerDiscovery.cancelCommissionableDeviceDiscovery(scanner, identifierData));
551
584
  }
552
585
 
586
+ /**
587
+ * Starts to discover commissionable devices.
588
+ * The promise will be fulfilled after the provided timeout or when the discovery is stopped via
589
+ * cancelCommissionableDeviceDiscovery(). The discoveredCallback will be called for each discovered device.
590
+ */
553
591
  async discoverCommissionableDevices(
554
592
  identifierData: CommissionableDeviceIdentifiers,
555
593
  discoveryCapabilities?: TypeFromPartialBitSchema<typeof DiscoveryCapabilitiesBitmap>,
556
594
  discoveredCallback?: (device: CommissionableDevice) => void,
557
595
  timeoutSeconds = 900,
558
596
  ) {
559
- this.assertIsAddedToMatterServer();
560
- const controller = this.assertControllerIsStarted();
597
+ this.#assertIsAddedToMatterServer();
598
+ const controller = this.#assertControllerIsStarted();
561
599
  return await ControllerDiscovery.discoverCommissionableDevices(
562
600
  controller.collectScanners(discoveryCapabilities),
563
601
  timeoutSeconds,
@@ -566,11 +604,15 @@ export class CommissioningController extends MatterNode {
566
604
  );
567
605
  }
568
606
 
607
+ /**
608
+ * Use this method to reset the Controller storage. The method can only be called if the controller is stopped and
609
+ * will remove all commissioning data and paired nodes from the controller.
610
+ */
569
611
  async resetStorage() {
570
- this.assertControllerIsStarted(
612
+ this.#assertControllerIsStarted(
571
613
  "Storage cannot be reset while the controller is operating! Please close the controller first.",
572
614
  );
573
- const { storage, environment } = this.assertIsAddedToMatterServer();
615
+ const { storage, environment } = this.#assertIsAddedToMatterServer();
574
616
  if (environment !== undefined) {
575
617
  const controllerStore = environment.get(ControllerStore);
576
618
  await controllerStore.erase();
@@ -583,12 +625,13 @@ export class CommissioningController extends MatterNode {
583
625
 
584
626
  /** Returns active session information for all connected nodes. */
585
627
  getActiveSessionInformation() {
586
- return this.controllerInstance?.getActiveSessionInformation() ?? [];
628
+ return this.#controllerInstance?.getActiveSessionInformation() ?? [];
587
629
  }
588
630
 
631
+ /** @private */
589
632
  async validateAndUpdateFabricLabel(nodeId: NodeId) {
590
- const controller = this.assertControllerIsStarted();
591
- const node = this.initializedNodes.get(nodeId);
633
+ const controller = this.#assertControllerIsStarted();
634
+ const node = this.#initializedNodes.get(nodeId);
592
635
  if (node === undefined) {
593
636
  throw new ImplementationError(`Node ${nodeId} is not connected!`);
594
637
  }
@@ -614,14 +657,18 @@ export class CommissioningController extends MatterNode {
614
657
  }
615
658
  }
616
659
 
660
+ /**
661
+ * Updates the fabric label for the controller and all connected nodes.
662
+ * The label is used to identify the controller and all connected nodes in the fabric.
663
+ */
617
664
  async updateFabricLabel(label: string) {
618
- const controller = this.assertControllerIsStarted();
665
+ const controller = this.#assertControllerIsStarted();
619
666
  if (controller.fabricConfig.label === label) {
620
667
  return;
621
668
  }
622
669
  await controller.updateFabricLabel(label);
623
670
 
624
- for (const node of this.initializedNodes.values()) {
671
+ for (const node of this.#initializedNodes.values()) {
625
672
  if (node.isConnected) {
626
673
  // When Node is connected, update the fabric label on the node directly
627
674
  try {
@@ -643,14 +690,14 @@ export class CommissioningController extends MatterNode {
643
690
 
644
691
  // If no update handler is registered, register one
645
692
  // TODO: Convert this next to a task system for node tasks and also better handle error cases
646
- if (!this.nodeUpdateLabelHandlers.has(node.nodeId)) {
693
+ if (!this.#nodeUpdateLabelHandlers.has(node.nodeId)) {
647
694
  const updateOnReconnect = (nodeState: NodeStates) => {
648
695
  if (nodeState === NodeStates.Connected) {
649
696
  this.validateAndUpdateFabricLabel(node.nodeId)
650
697
  .catch(error => logger.warn(`Error updating fabric label on node ${node.nodeId}:`, error))
651
698
  .finally(() => {
652
699
  node.events.stateChanged.off(updateOnReconnect);
653
- this.nodeUpdateLabelHandlers.delete(node.nodeId);
700
+ this.#nodeUpdateLabelHandlers.delete(node.nodeId);
654
701
  });
655
702
  }
656
703
  };