@project-chip/matter.js 0.12.3 → 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.
- package/dist/cjs/CommissioningController.d.ts +52 -30
- package/dist/cjs/CommissioningController.d.ts.map +1 -1
- package/dist/cjs/CommissioningController.js +154 -109
- package/dist/cjs/CommissioningController.js.map +1 -1
- package/dist/cjs/device/PairedNode.d.ts +22 -9
- package/dist/cjs/device/PairedNode.d.ts.map +1 -1
- package/dist/cjs/device/PairedNode.js +43 -31
- package/dist/cjs/device/PairedNode.js.map +1 -1
- package/dist/esm/CommissioningController.d.ts +52 -30
- package/dist/esm/CommissioningController.d.ts.map +1 -1
- package/dist/esm/CommissioningController.js +154 -109
- package/dist/esm/CommissioningController.js.map +1 -1
- package/dist/esm/device/PairedNode.d.ts +22 -9
- package/dist/esm/device/PairedNode.d.ts.map +1 -1
- package/dist/esm/device/PairedNode.js +43 -31
- package/dist/esm/device/PairedNode.js.map +1 -1
- package/package.json +8 -8
- package/src/CommissioningController.ts +155 -108
- package/src/device/PairedNode.ts +48 -35
package/src/device/PairedNode.ts
CHANGED
|
@@ -257,6 +257,9 @@ export class PairedNode {
|
|
|
257
257
|
#construction: Construction<PairedNode>;
|
|
258
258
|
#clientReconnectInProgress = false;
|
|
259
259
|
#currentSubscriptionHandler?: SubscriptionHandlerCallbacks;
|
|
260
|
+
readonly #commissioningController: CommissioningController;
|
|
261
|
+
#options: CommissioningControllerNodeOptions;
|
|
262
|
+
readonly #reconnectFunc: (discoveryType?: NodeDiscoveryType, noForcedConnection?: boolean) => Promise<void>;
|
|
260
263
|
|
|
261
264
|
readonly events = {
|
|
262
265
|
/**
|
|
@@ -318,14 +321,11 @@ export class PairedNode {
|
|
|
318
321
|
|
|
319
322
|
constructor(
|
|
320
323
|
readonly nodeId: NodeId,
|
|
321
|
-
|
|
322
|
-
|
|
324
|
+
commissioningController: CommissioningController,
|
|
325
|
+
options: CommissioningControllerNodeOptions = {},
|
|
323
326
|
knownNodeDetails: DeviceInformationData,
|
|
324
327
|
interactionClient: InteractionClient,
|
|
325
|
-
|
|
326
|
-
discoveryType?: NodeDiscoveryType,
|
|
327
|
-
noForcedConnection?: boolean,
|
|
328
|
-
) => Promise<void>,
|
|
328
|
+
reconnectFunc: (discoveryType?: NodeDiscoveryType, noForcedConnection?: boolean) => Promise<void>,
|
|
329
329
|
assignDisconnectedHandler: (handler: () => Promise<void>) => void,
|
|
330
330
|
sessions: BasicSet<SecureSession, SecureSession>,
|
|
331
331
|
storedAttributeData?: DecodedAttributeReportValue<any>[],
|
|
@@ -341,9 +341,13 @@ export class PairedNode {
|
|
|
341
341
|
}
|
|
342
342
|
});
|
|
343
343
|
|
|
344
|
+
this.#commissioningController = commissioningController;
|
|
345
|
+
this.#options = options;
|
|
346
|
+
this.#reconnectFunc = reconnectFunc;
|
|
347
|
+
|
|
344
348
|
this.#interactionClient = interactionClient;
|
|
345
349
|
this.#interactionClient.channelUpdated.on(() => {
|
|
346
|
-
// When we planned
|
|
350
|
+
// When we had planned a reconnect because of a disconnect we can stop the timer now
|
|
347
351
|
if (
|
|
348
352
|
this.#reconnectDelayTimer?.isRunning &&
|
|
349
353
|
!this.#clientReconnectInProgress &&
|
|
@@ -376,7 +380,7 @@ export class PairedNode {
|
|
|
376
380
|
await this.#initializeFromStoredData(storedAttributeData);
|
|
377
381
|
}
|
|
378
382
|
|
|
379
|
-
if (this
|
|
383
|
+
if (this.#options.autoConnect !== false) {
|
|
380
384
|
// This kicks of the remote initialization and automatic reconnection handling if it can not be connected
|
|
381
385
|
this.#initialize().catch(error => {
|
|
382
386
|
logger.info(`Node ${nodeId}: Error during remote initialization`, error);
|
|
@@ -397,26 +401,32 @@ export class PairedNode {
|
|
|
397
401
|
return this.#connectionState === NodeStates.Connected;
|
|
398
402
|
}
|
|
399
403
|
|
|
404
|
+
/** Returns the Node connection state. */
|
|
400
405
|
get state() {
|
|
401
406
|
return this.#connectionState;
|
|
402
407
|
}
|
|
403
408
|
|
|
409
|
+
/** Returns the BasicInformation cluster metadata collected from the device. */
|
|
404
410
|
get basicInformation() {
|
|
405
411
|
return this.#nodeDetails.basicInformation;
|
|
406
412
|
}
|
|
407
413
|
|
|
414
|
+
/** Returns the general capability metadata collected from the device. */
|
|
408
415
|
get deviceInformation() {
|
|
409
416
|
return this.#nodeDetails.meta;
|
|
410
417
|
}
|
|
411
418
|
|
|
419
|
+
/** Is the Node fully initialized with formerly stored subscription data? False when the node was never connected so far. */
|
|
412
420
|
get localInitializationDone() {
|
|
413
421
|
return this.#localInitializationDone;
|
|
414
422
|
}
|
|
415
423
|
|
|
424
|
+
/** Is the Node fully initialized with remote subscription or read data? */
|
|
416
425
|
get remoteInitializationDone() {
|
|
417
426
|
return this.#remoteInitializationDone;
|
|
418
427
|
}
|
|
419
428
|
|
|
429
|
+
/** Is the Node initialized - locally or remotely? */
|
|
420
430
|
get initialized() {
|
|
421
431
|
return this.#remoteInitializationDone || this.#localInitializationDone;
|
|
422
432
|
}
|
|
@@ -438,7 +448,7 @@ export class PairedNode {
|
|
|
438
448
|
)
|
|
439
449
|
return;
|
|
440
450
|
this.#connectionState = state;
|
|
441
|
-
this
|
|
451
|
+
this.#options.stateInformationCallback?.(this.nodeId, state as unknown as NodeStateInformation);
|
|
442
452
|
this.events.stateChanged.emit(state);
|
|
443
453
|
if (state === NodeStates.Disconnected) {
|
|
444
454
|
this.#reconnectDelayTimer?.stop();
|
|
@@ -454,7 +464,7 @@ export class PairedNode {
|
|
|
454
464
|
|
|
455
465
|
this.#clientReconnectInProgress = true;
|
|
456
466
|
try {
|
|
457
|
-
await this
|
|
467
|
+
await this.#reconnectFunc(discoveryType);
|
|
458
468
|
} finally {
|
|
459
469
|
this.#clientReconnectInProgress = false;
|
|
460
470
|
}
|
|
@@ -462,19 +472,20 @@ export class PairedNode {
|
|
|
462
472
|
|
|
463
473
|
/**
|
|
464
474
|
* Schedule a connection to the device. This method is non-blocking and will return immediately.
|
|
465
|
-
* The connection happens in the background. Please monitor the state of the node to see if the
|
|
475
|
+
* The connection happens in the background. Please monitor the state events of the node to see if the
|
|
466
476
|
* connection was successful.
|
|
477
|
+
* The provided connection options will be set and used internally if the node reconnects successfully.
|
|
467
478
|
*/
|
|
468
479
|
connect(connectOptions?: CommissioningControllerNodeOptions) {
|
|
469
480
|
if (connectOptions !== undefined) {
|
|
470
|
-
this
|
|
481
|
+
this.#options = connectOptions;
|
|
471
482
|
}
|
|
472
483
|
this.triggerReconnect();
|
|
473
484
|
}
|
|
474
485
|
|
|
475
486
|
/**
|
|
476
487
|
* Trigger a reconnection to the device. This method is non-blocking and will return immediately.
|
|
477
|
-
* The reconnection happens in the background. Please monitor the state of the node to see if the
|
|
488
|
+
* The reconnection happens in the background. Please monitor the state events of the node to see if the
|
|
478
489
|
* reconnection was successful.
|
|
479
490
|
*/
|
|
480
491
|
triggerReconnect() {
|
|
@@ -496,7 +507,7 @@ export class PairedNode {
|
|
|
496
507
|
*/
|
|
497
508
|
async reconnect(connectOptions?: CommissioningControllerNodeOptions) {
|
|
498
509
|
if (connectOptions !== undefined) {
|
|
499
|
-
this
|
|
510
|
+
this.#options = connectOptions;
|
|
500
511
|
}
|
|
501
512
|
if (this.#reconnectionInProgress || this.#remoteInitializationInProgress) {
|
|
502
513
|
logger.debug(
|
|
@@ -583,7 +594,7 @@ export class PairedNode {
|
|
|
583
594
|
}
|
|
584
595
|
|
|
585
596
|
async #initializeFromStoredData(storedAttributeData: DecodedAttributeReportValue<any>[]) {
|
|
586
|
-
const { autoSubscribe } = this
|
|
597
|
+
const { autoSubscribe } = this.#options;
|
|
587
598
|
if (this.#remoteInitializationDone || this.#localInitializationDone || autoSubscribe === false) return;
|
|
588
599
|
|
|
589
600
|
// Minimum sanity check that we have at least data for the Root endpoint and one other endpoint to initialize
|
|
@@ -621,7 +632,7 @@ export class PairedNode {
|
|
|
621
632
|
try {
|
|
622
633
|
// Enforce a new Connection
|
|
623
634
|
await this.#ensureConnection(true);
|
|
624
|
-
const { autoSubscribe, attributeChangedCallback, eventTriggeredCallback } = this
|
|
635
|
+
const { autoSubscribe, attributeChangedCallback, eventTriggeredCallback } = this.#options;
|
|
625
636
|
|
|
626
637
|
let deviceDetailsUpdated = false;
|
|
627
638
|
// We need to query some Device metadata because we do not have them (or update them anyway)
|
|
@@ -664,7 +675,7 @@ export class PairedNode {
|
|
|
664
675
|
}
|
|
665
676
|
if (!this.#remoteInitializationDone) {
|
|
666
677
|
try {
|
|
667
|
-
await this
|
|
678
|
+
await this.#commissioningController.validateAndUpdateFabricLabel(this.nodeId);
|
|
668
679
|
} catch (error) {
|
|
669
680
|
logger.info(`Node ${this.nodeId}: Error updating fabric label`, error);
|
|
670
681
|
}
|
|
@@ -683,8 +694,9 @@ export class PairedNode {
|
|
|
683
694
|
}
|
|
684
695
|
|
|
685
696
|
/**
|
|
686
|
-
* Request the current InteractionClient for custom special
|
|
687
|
-
* ClusterClients of the Devices of the node should be used instead.
|
|
697
|
+
* Request the current InteractionClient for custom special interactions with the device. Usually the
|
|
698
|
+
* ClusterClients of the Devices of the node should be used instead. An own InteractionClient is only needed
|
|
699
|
+
* when you want to read or write multiple attributes or events in a single request or send batch invokes.
|
|
688
700
|
*/
|
|
689
701
|
getInteractionClient() {
|
|
690
702
|
return this.#ensureConnection();
|
|
@@ -714,7 +726,7 @@ export class PairedNode {
|
|
|
714
726
|
let { ignoreInitialTriggers = false } = options;
|
|
715
727
|
|
|
716
728
|
const { minIntervalFloorSeconds, maxIntervalCeilingSeconds } =
|
|
717
|
-
this.#nodeDetails.determineSubscriptionParameters(this
|
|
729
|
+
this.#nodeDetails.determineSubscriptionParameters(this.#options);
|
|
718
730
|
const { threadConnected } = this.#nodeDetails.meta ?? {};
|
|
719
731
|
|
|
720
732
|
this.#invalidateSubscriptionHandler();
|
|
@@ -835,6 +847,7 @@ export class PairedNode {
|
|
|
835
847
|
return initialSubscriptionData;
|
|
836
848
|
}
|
|
837
849
|
|
|
850
|
+
/** Read all attributes of the devices and return them. If a stored state exists this is used to minimize needed traffic. */
|
|
838
851
|
async readAllAttributes() {
|
|
839
852
|
return this.#interactionClient.getAllAttributes({
|
|
840
853
|
dataVersionFilters: this.#interactionClient.getCachedClusterDataVersions(),
|
|
@@ -909,7 +922,7 @@ export class PairedNode {
|
|
|
909
922
|
async #updateEndpointStructure() {
|
|
910
923
|
const allClusterAttributes = await this.readAllAttributes();
|
|
911
924
|
await this.#initializeEndpointStructure(allClusterAttributes, true);
|
|
912
|
-
this
|
|
925
|
+
this.#options.stateInformationCallback?.(this.nodeId, NodeStateInformation.StructureChanged);
|
|
913
926
|
this.events.structureChanged.emit();
|
|
914
927
|
}
|
|
915
928
|
|
|
@@ -1029,14 +1042,7 @@ export class PairedNode {
|
|
|
1029
1042
|
}
|
|
1030
1043
|
}
|
|
1031
1044
|
|
|
1032
|
-
/**
|
|
1033
|
-
* Create a device object from the data read from the device.
|
|
1034
|
-
*
|
|
1035
|
-
* @param endpointId Endpoint ID
|
|
1036
|
-
* @param data Data of all clusters read from the device
|
|
1037
|
-
* @param interactionClient InteractionClient to use for the device
|
|
1038
|
-
* @private
|
|
1039
|
-
*/
|
|
1045
|
+
/** Create a device object from the data read from the device. */
|
|
1040
1046
|
#createDevice(
|
|
1041
1047
|
endpointId: EndpointNumber,
|
|
1042
1048
|
data: { [key: ClusterId]: { [key: string]: any } },
|
|
@@ -1136,7 +1142,7 @@ export class PairedNode {
|
|
|
1136
1142
|
}
|
|
1137
1143
|
}
|
|
1138
1144
|
|
|
1139
|
-
/** Returns the functional devices/endpoints (
|
|
1145
|
+
/** Returns the functional devices/endpoints (the "childs" of the Root Endpoint) known for this node. */
|
|
1140
1146
|
getDevices(): EndpointInterface[] {
|
|
1141
1147
|
return this.#endpoints.get(EndpointNumber(0))?.getChildEndpoints() ?? [];
|
|
1142
1148
|
}
|
|
@@ -1146,13 +1152,14 @@ export class PairedNode {
|
|
|
1146
1152
|
return this.#endpoints.get(EndpointNumber(endpointId));
|
|
1147
1153
|
}
|
|
1148
1154
|
|
|
1155
|
+
/** Returns the Root Endpoint of the device. */
|
|
1149
1156
|
getRootEndpoint() {
|
|
1150
1157
|
return this.getDeviceById(0);
|
|
1151
1158
|
}
|
|
1152
1159
|
|
|
1153
1160
|
/** De-Commission (unpair) the device from this controller by removing the fabric from the device. */
|
|
1154
1161
|
async decommission() {
|
|
1155
|
-
if (!this
|
|
1162
|
+
if (!this.#commissioningController.isNodeCommissioned(this.nodeId)) {
|
|
1156
1163
|
throw new ImplementationError(`This Node ${this.nodeId} is not commissioned.`);
|
|
1157
1164
|
}
|
|
1158
1165
|
if (
|
|
@@ -1180,10 +1187,14 @@ export class PairedNode {
|
|
|
1180
1187
|
);
|
|
1181
1188
|
}
|
|
1182
1189
|
this.#setConnectionState(NodeStates.Disconnected);
|
|
1183
|
-
await this
|
|
1190
|
+
await this.#commissioningController.removeNode(this.nodeId, false);
|
|
1184
1191
|
}
|
|
1185
1192
|
|
|
1186
|
-
/**
|
|
1193
|
+
/**
|
|
1194
|
+
* Opens a Basic Commissioning Window (uses the original Passcode printed on the device) with the device.
|
|
1195
|
+
* This is an optional method, so it might not be supported by all devices and could be rejected with an error in
|
|
1196
|
+
* this case! Better use openEnhancedCommissioningWindow() instead.
|
|
1197
|
+
*/
|
|
1187
1198
|
async openBasicCommissioningWindow(commissioningTimeout = 900 /* 15 minutes */) {
|
|
1188
1199
|
const adminCommissioningCluster = this.getRootClusterClient(AdministratorCommissioning.Cluster.with("Basic"));
|
|
1189
1200
|
if (adminCommissioningCluster === undefined) {
|
|
@@ -1277,18 +1288,20 @@ export class PairedNode {
|
|
|
1277
1288
|
};
|
|
1278
1289
|
}
|
|
1279
1290
|
|
|
1291
|
+
/** Closes the current session, ends the subscription and disconnects the device. */
|
|
1280
1292
|
async disconnect() {
|
|
1281
1293
|
this.close();
|
|
1282
|
-
await this
|
|
1294
|
+
await this.#commissioningController.disconnectNode(this.nodeId);
|
|
1283
1295
|
}
|
|
1284
1296
|
|
|
1297
|
+
/** Closes the current subscription and ends all timers for reconnects or such used by this PairedNode instance. */
|
|
1285
1298
|
close(sendDecommissionedStatus = false) {
|
|
1286
1299
|
this.#newChannelReconnectDelayTimer.stop();
|
|
1287
1300
|
this.#reconnectDelayTimer?.stop();
|
|
1288
1301
|
this.#reconnectDelayTimer = undefined;
|
|
1289
1302
|
this.#updateEndpointStructureTimer.stop();
|
|
1290
1303
|
if (sendDecommissionedStatus) {
|
|
1291
|
-
this
|
|
1304
|
+
this.#options.stateInformationCallback?.(this.nodeId, NodeStateInformation.Decommissioned);
|
|
1292
1305
|
this.events.decommissioned.emit();
|
|
1293
1306
|
}
|
|
1294
1307
|
this.#setConnectionState(NodeStates.Disconnected);
|