@project-chip/matter.js 0.15.4 → 0.15.6
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 +2 -1
- package/dist/cjs/CommissioningController.d.ts.map +1 -1
- package/dist/cjs/CommissioningController.js +26 -35
- package/dist/cjs/CommissioningController.js.map +1 -1
- package/dist/cjs/MatterController.d.ts.map +1 -1
- package/dist/cjs/MatterController.js +2 -2
- package/dist/cjs/MatterController.js.map +1 -1
- package/dist/cjs/device/CachedClientNodeStore.d.ts +4 -3
- package/dist/cjs/device/CachedClientNodeStore.d.ts.map +1 -1
- package/dist/cjs/device/CachedClientNodeStore.js +19 -2
- package/dist/cjs/device/CachedClientNodeStore.js.map +1 -1
- package/dist/cjs/device/Endpoint.d.ts +1 -1
- package/dist/cjs/device/Endpoint.d.ts.map +1 -1
- package/dist/cjs/device/Endpoint.js.map +1 -1
- package/dist/cjs/device/PairedNode.d.ts +56 -28
- package/dist/cjs/device/PairedNode.d.ts.map +1 -1
- package/dist/cjs/device/PairedNode.js +217 -78
- package/dist/cjs/device/PairedNode.js.map +1 -1
- package/dist/esm/CommissioningController.d.ts +2 -1
- package/dist/esm/CommissioningController.d.ts.map +1 -1
- package/dist/esm/CommissioningController.js +26 -35
- package/dist/esm/CommissioningController.js.map +1 -1
- package/dist/esm/MatterController.d.ts.map +1 -1
- package/dist/esm/MatterController.js +2 -3
- package/dist/esm/MatterController.js.map +1 -1
- package/dist/esm/device/CachedClientNodeStore.d.ts +4 -3
- package/dist/esm/device/CachedClientNodeStore.d.ts.map +1 -1
- package/dist/esm/device/CachedClientNodeStore.js +19 -2
- package/dist/esm/device/CachedClientNodeStore.js.map +1 -1
- package/dist/esm/device/Endpoint.d.ts +1 -1
- package/dist/esm/device/Endpoint.d.ts.map +1 -1
- package/dist/esm/device/Endpoint.js.map +1 -1
- package/dist/esm/device/PairedNode.d.ts +56 -28
- package/dist/esm/device/PairedNode.d.ts.map +1 -1
- package/dist/esm/device/PairedNode.js +218 -79
- package/dist/esm/device/PairedNode.js.map +1 -1
- package/package.json +8 -8
- package/src/CommissioningController.ts +31 -38
- package/src/MatterController.ts +3 -4
- package/src/device/CachedClientNodeStore.ts +24 -4
- package/src/device/Endpoint.ts +1 -1
- package/src/device/PairedNode.ts +322 -94
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
* Copyright 2022-2025 Matter.js Authors
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
|
+
import { Descriptor } from "#clusters";
|
|
6
7
|
import { AsyncObservable, BasicSet, Construction, Crypto, Diagnostic, MatterError, Observable } from "#general";
|
|
7
|
-
import { ClusterClientObj, DecodedAttributeReportValue, DecodedEventReportValue, InteractionClient, NodeDiscoveryType, NodeSession } from "#protocol";
|
|
8
|
+
import { AttributeClientValues, ClusterClientObj, DecodedAttributeReportValue, DecodedEventReportValue, InteractionClient, NodeDiscoveryType, NodeSession, StructuredReadAttributeData } from "#protocol";
|
|
8
9
|
import { ClusterType, EndpointNumber, NodeId } from "#types";
|
|
9
10
|
import { ClusterServerObj } from "../cluster/server/ClusterServerTypes.js";
|
|
10
11
|
import { CommissioningController } from "../CommissioningController.js";
|
|
@@ -110,6 +111,7 @@ export type CommissioningControllerNodeOptions = {
|
|
|
110
111
|
};
|
|
111
112
|
export declare class NodeNotConnectedError extends MatterError {
|
|
112
113
|
}
|
|
114
|
+
type DescriptorData = AttributeClientValues<typeof Descriptor.Complete.attributes>;
|
|
113
115
|
/**
|
|
114
116
|
* Class to represents one node that is paired/commissioned with the matter.js Controller. Instances are returned by
|
|
115
117
|
* the CommissioningController on commissioning or when connecting.
|
|
@@ -117,33 +119,7 @@ export declare class NodeNotConnectedError extends MatterError {
|
|
|
117
119
|
export declare class PairedNode {
|
|
118
120
|
#private;
|
|
119
121
|
readonly nodeId: NodeId;
|
|
120
|
-
readonly events:
|
|
121
|
-
/**
|
|
122
|
-
* Emitted when the node is initialized from local data. These data usually are stale, but you can still already
|
|
123
|
-
* use the node to interact with the device. If no local data are available this event will be emitted together
|
|
124
|
-
* with the initializedFromRemote event.
|
|
125
|
-
*/
|
|
126
|
-
initialized: AsyncObservable<[details: DeviceInformationData], void>;
|
|
127
|
-
/**
|
|
128
|
-
* Emitted when the node is fully initialized from remote and all attributes and events are subscribed.
|
|
129
|
-
* This event can also be awaited if code needs to be blocked until the node is fully initialized.
|
|
130
|
-
*/
|
|
131
|
-
initializedFromRemote: AsyncObservable<[details: DeviceInformationData], void>;
|
|
132
|
-
/** Emitted when the state of the node changes. */
|
|
133
|
-
stateChanged: Observable<[nodeState: NodeStates], void>;
|
|
134
|
-
/**
|
|
135
|
-
* Emitted when an attribute value changes. If the oldValue is undefined then no former value was known.
|
|
136
|
-
*/
|
|
137
|
-
attributeChanged: Observable<[data: DecodedAttributeReportValue<any>, oldValue: any], void>;
|
|
138
|
-
/** Emitted when an event is triggered. */
|
|
139
|
-
eventTriggered: Observable<[DecodedEventReportValue<any>], void>;
|
|
140
|
-
/** Emitted when the structure of the node changes (Endpoints got added or also removed). */
|
|
141
|
-
structureChanged: Observable<[void], void>;
|
|
142
|
-
/** Emitted when the node is decommissioned. */
|
|
143
|
-
decommissioned: Observable<[void], void>;
|
|
144
|
-
/** Emitted when a subscription alive trigger is received (max interval trigger or any data update) */
|
|
145
|
-
connectionAlive: Observable<[void], void>;
|
|
146
|
-
};
|
|
122
|
+
readonly events: PairedNode.Events;
|
|
147
123
|
static create(nodeId: NodeId, commissioningController: CommissioningController, options: CommissioningControllerNodeOptions | undefined, knownNodeDetails: DeviceInformationData, interactionClient: InteractionClient, reconnectFunc: (discoveryType?: NodeDiscoveryType, noForcedConnection?: boolean) => Promise<void>, assignDisconnectedHandler: (handler: () => Promise<void>) => void, sessions: BasicSet<NodeSession>, crypto: Crypto, storedAttributeData?: DecodedAttributeReportValue<any>[]): Promise<PairedNode>;
|
|
148
124
|
constructor(nodeId: NodeId, commissioningController: CommissioningController, options: CommissioningControllerNodeOptions | undefined, knownNodeDetails: DeviceInformationData, interactionClient: InteractionClient, reconnectFunc: (discoveryType?: NodeDiscoveryType, noForcedConnection?: boolean) => Promise<void>, assignDisconnectedHandler: (handler: () => Promise<void>) => void, sessions: BasicSet<NodeSession, NodeSession>, crypto: Crypto, storedAttributeData?: DecodedAttributeReportValue<any>[]);
|
|
149
125
|
get construction(): Construction<PairedNode>;
|
|
@@ -206,6 +182,12 @@ export declare class PairedNode {
|
|
|
206
182
|
}>;
|
|
207
183
|
/** Read all attributes of the devices and return them. If a stored state exists this is used to minimize needed traffic. */
|
|
208
184
|
readAllAttributes(): Promise<DecodedAttributeReportValue<any>[]>;
|
|
185
|
+
/**
|
|
186
|
+
* Traverse the structure data and collect all data for the given endpointId.
|
|
187
|
+
* Return true if data for the endpoint was found, otherwise false.
|
|
188
|
+
* If data was found it is added to the collectedData map.
|
|
189
|
+
*/
|
|
190
|
+
collectDescriptorData(structure: StructuredReadAttributeData, endpointId: EndpointNumber, collectedData: Map<EndpointNumber, DescriptorData>): void;
|
|
209
191
|
/** Returns the functional devices/endpoints (the "childs" of the Root Endpoint) known for this node. */
|
|
210
192
|
getDevices(): Endpoint[];
|
|
211
193
|
/** Returns the device/endpoint with the given endpoint ID. */
|
|
@@ -257,4 +239,50 @@ export declare class PairedNode {
|
|
|
257
239
|
getClusterClientForDevice<const T extends ClusterType>(endpointId: EndpointNumber, cluster: T): ClusterClientObj<T> | undefined;
|
|
258
240
|
get [Diagnostic.value](): unknown;
|
|
259
241
|
}
|
|
242
|
+
export declare namespace PairedNode {
|
|
243
|
+
interface NodeStructureEvents {
|
|
244
|
+
/** Emitted when endpoints are added. */
|
|
245
|
+
nodeEndpointAdded: Observable<[EndpointNumber]>;
|
|
246
|
+
/** Emitted when endpoints are removed. */
|
|
247
|
+
nodeEndpointRemoved: Observable<[EndpointNumber]>;
|
|
248
|
+
/** Emitted when endpoints are updated (e.g. device type changed, structure changed). */
|
|
249
|
+
nodeEndpointChanged: Observable<[EndpointNumber]>;
|
|
250
|
+
}
|
|
251
|
+
interface Events extends NodeStructureEvents {
|
|
252
|
+
/**
|
|
253
|
+
* Emitted when the node is initialized from local data. These data usually are stale, but you can still already
|
|
254
|
+
* use the node to interact with the device. If no local data are available this event will be emitted together
|
|
255
|
+
* with the initializedFromRemote event.
|
|
256
|
+
*/
|
|
257
|
+
initialized: AsyncObservable<[details: DeviceInformationData]>;
|
|
258
|
+
/**
|
|
259
|
+
* Emitted when the node is fully initialized from remote and all attributes and events are subscribed.
|
|
260
|
+
* This event can also be awaited if code needs to be blocked until the node is fully initialized.
|
|
261
|
+
*/
|
|
262
|
+
initializedFromRemote: AsyncObservable<[details: DeviceInformationData]>;
|
|
263
|
+
/**
|
|
264
|
+
* Emitted when the device information changes.
|
|
265
|
+
*/
|
|
266
|
+
deviceInformationChanged: AsyncObservable<[details: DeviceInformationData]>;
|
|
267
|
+
/** Emitted when the state of the node changes. */
|
|
268
|
+
stateChanged: Observable<[nodeState: NodeStates]>;
|
|
269
|
+
/**
|
|
270
|
+
* Emitted when an attribute value changes. If the oldValue is undefined then no former value was known.
|
|
271
|
+
*/
|
|
272
|
+
attributeChanged: Observable<[data: DecodedAttributeReportValue<any>, oldValue: any]>;
|
|
273
|
+
/** Emitted when an event is triggered. */
|
|
274
|
+
eventTriggered: Observable<[DecodedEventReportValue<any>]>;
|
|
275
|
+
/**
|
|
276
|
+
* Emitted when all node structure changes were applied (Endpoints got added or also removed).
|
|
277
|
+
* You can alternatively use the nodeEndpointAdded, nodeEndpointRemoved and nodeEndpointChanged events to react on specific changes.
|
|
278
|
+
* This event is emitted after all nodeEndpointAdded, nodeEndpointRemoved and nodeEndpointChanged events are emitted.
|
|
279
|
+
*/
|
|
280
|
+
structureChanged: Observable<[void]>;
|
|
281
|
+
/** Emitted when the node is decommissioned. */
|
|
282
|
+
decommissioned: Observable<[void]>;
|
|
283
|
+
/** Emitted when a subscription alive trigger is received (max interval trigger or any data update) */
|
|
284
|
+
connectionAlive: Observable<[void]>;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
export {};
|
|
260
288
|
//# sourceMappingURL=PairedNode.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PairedNode.d.ts","sourceRoot":"","sources":["../../../src/device/PairedNode.ts"],"names":[],"mappings":"AAAA;;;;GAIG;
|
|
1
|
+
{"version":3,"file":"PairedNode.d.ts","sourceRoot":"","sources":["../../../src/device/PairedNode.ts"],"names":[],"mappings":"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"}
|
|
@@ -66,6 +66,15 @@ var NodeStateInformation = /* @__PURE__ */ ((NodeStateInformation2) => {
|
|
|
66
66
|
})(NodeStateInformation || {});
|
|
67
67
|
class NodeNotConnectedError extends import_general.MatterError {
|
|
68
68
|
}
|
|
69
|
+
function areNumberListsSame(list1, list2) {
|
|
70
|
+
const set1 = new Set(list1);
|
|
71
|
+
const set2 = new Set(list2);
|
|
72
|
+
if (set1.size !== set2.size) return false;
|
|
73
|
+
for (const entry of set1.values()) {
|
|
74
|
+
if (!set2.has(entry)) return false;
|
|
75
|
+
}
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
69
78
|
class PairedNode {
|
|
70
79
|
constructor(nodeId, commissioningController, options = {}, knownNodeDetails, interactionClient, reconnectFunc, assignDisconnectedHandler, sessions, crypto, storedAttributeData) {
|
|
71
80
|
this.nodeId = nodeId;
|
|
@@ -159,31 +168,25 @@ class PairedNode {
|
|
|
159
168
|
#reconnectFunc;
|
|
160
169
|
#currentSubscriptionIntervalS;
|
|
161
170
|
#crypto;
|
|
171
|
+
#deviceInformationUpdateNeeded = false;
|
|
172
|
+
/**
|
|
173
|
+
* Endpoint structure change information that are checked when updating structure
|
|
174
|
+
* - null means that the endpoint itself changed, so will be regenerated completely any case
|
|
175
|
+
* - array of ClusterIds means that only these clusters changed and will be updated
|
|
176
|
+
*/
|
|
177
|
+
#registeredEndpointStructureChanges = /* @__PURE__ */ new Map();
|
|
162
178
|
events = {
|
|
163
|
-
/**
|
|
164
|
-
* Emitted when the node is initialized from local data. These data usually are stale, but you can still already
|
|
165
|
-
* use the node to interact with the device. If no local data are available this event will be emitted together
|
|
166
|
-
* with the initializedFromRemote event.
|
|
167
|
-
*/
|
|
168
179
|
initialized: (0, import_general.AsyncObservable)(),
|
|
169
|
-
/**
|
|
170
|
-
* Emitted when the node is fully initialized from remote and all attributes and events are subscribed.
|
|
171
|
-
* This event can also be awaited if code needs to be blocked until the node is fully initialized.
|
|
172
|
-
*/
|
|
173
180
|
initializedFromRemote: (0, import_general.AsyncObservable)(),
|
|
174
|
-
|
|
181
|
+
deviceInformationChanged: (0, import_general.AsyncObservable)(),
|
|
175
182
|
stateChanged: (0, import_general.Observable)(),
|
|
176
|
-
/**
|
|
177
|
-
* Emitted when an attribute value changes. If the oldValue is undefined then no former value was known.
|
|
178
|
-
*/
|
|
179
183
|
attributeChanged: (0, import_general.Observable)(),
|
|
180
|
-
/** Emitted when an event is triggered. */
|
|
181
184
|
eventTriggered: (0, import_general.Observable)(),
|
|
182
|
-
/** Emitted when the structure of the node changes (Endpoints got added or also removed). */
|
|
183
185
|
structureChanged: (0, import_general.Observable)(),
|
|
184
|
-
|
|
186
|
+
nodeEndpointAdded: (0, import_general.Observable)(),
|
|
187
|
+
nodeEndpointRemoved: (0, import_general.Observable)(),
|
|
188
|
+
nodeEndpointChanged: (0, import_general.Observable)(),
|
|
185
189
|
decommissioned: (0, import_general.Observable)(),
|
|
186
|
-
/** Emitted when a subscription alive trigger is received (max interval trigger or any data update) */
|
|
187
190
|
connectionAlive: (0, import_general.Observable)()
|
|
188
191
|
};
|
|
189
192
|
static async create(nodeId, commissioningController, options = {}, knownNodeDetails, interactionClient, reconnectFunc, assignDisconnectedHandler, sessions, crypto, storedAttributeData) {
|
|
@@ -398,7 +401,7 @@ class PairedNode {
|
|
|
398
401
|
})) {
|
|
399
402
|
return;
|
|
400
403
|
}
|
|
401
|
-
await this.#initializeEndpointStructure(storedAttributeData);
|
|
404
|
+
await this.#initializeEndpointStructure(storedAttributeData, false);
|
|
402
405
|
await this.events.initialized.emit(this.#nodeDetails.toStorageData());
|
|
403
406
|
this.#localInitializationDone = true;
|
|
404
407
|
}
|
|
@@ -436,7 +439,7 @@ class PairedNode {
|
|
|
436
439
|
if (attributeReports === void 0) {
|
|
437
440
|
throw new import_general.InternalError("No attribute reports received when subscribing to all values!");
|
|
438
441
|
}
|
|
439
|
-
await this.#initializeEndpointStructure(attributeReports
|
|
442
|
+
await this.#initializeEndpointStructure(attributeReports);
|
|
440
443
|
this.#remoteInitializationInProgress = false;
|
|
441
444
|
if (!deviceDetailsUpdated) {
|
|
442
445
|
const rootEndpoint = this.getRootEndpoint();
|
|
@@ -447,7 +450,7 @@ class PairedNode {
|
|
|
447
450
|
this.#currentSubscriptionIntervalS = maxInterval;
|
|
448
451
|
} else {
|
|
449
452
|
const allClusterAttributes = await this.readAllAttributes();
|
|
450
|
-
await this.#initializeEndpointStructure(allClusterAttributes
|
|
453
|
+
await this.#initializeEndpointStructure(allClusterAttributes);
|
|
451
454
|
this.#remoteInitializationInProgress = false;
|
|
452
455
|
}
|
|
453
456
|
if (!this.#remoteInitializationDone) {
|
|
@@ -529,7 +532,7 @@ class PairedNode {
|
|
|
529
532
|
);
|
|
530
533
|
(0, import_TypeHelpers.asClusterClientInternal)(cluster)._triggerAttributeUpdate(attributeId, value);
|
|
531
534
|
attributeChangedCallback?.(data, oldValue);
|
|
532
|
-
this.#
|
|
535
|
+
this.#checkAttributesForNeededUpdates(endpointId, clusterId, attributeId);
|
|
533
536
|
},
|
|
534
537
|
eventListener: (data) => {
|
|
535
538
|
if (ignoreInitialTriggers) return;
|
|
@@ -586,18 +589,32 @@ class PairedNode {
|
|
|
586
589
|
this.#reconnectDelayTimer = void 0;
|
|
587
590
|
this.#setConnectionState(0 /* Connected */);
|
|
588
591
|
}
|
|
592
|
+
if (this.#remoteInitializationDone && this.#registeredEndpointStructureChanges.size > 0 && !this.#updateEndpointStructureTimer.isRunning) {
|
|
593
|
+
logger.info(`Node ${this.nodeId}: Endpoint structure needs to be updated ...`);
|
|
594
|
+
this.#updateEndpointStructureTimer.stop().start();
|
|
595
|
+
} else if (this.#deviceInformationUpdateNeeded) {
|
|
596
|
+
const rootEndpoint = this.getRootEndpoint();
|
|
597
|
+
if (rootEndpoint !== void 0) {
|
|
598
|
+
this.#nodeDetails.enhanceDeviceDetailsFromCache(rootEndpoint).then(() => this.events.deviceInformationChanged.emit(this.#nodeDetails.toStorageData())).catch(
|
|
599
|
+
(error) => logger.warn(
|
|
600
|
+
`Node ${this.nodeId}: Error updating device information from root endpoint`,
|
|
601
|
+
error
|
|
602
|
+
)
|
|
603
|
+
);
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
this.#deviceInformationUpdateNeeded = false;
|
|
589
607
|
this.events.connectionAlive.emit();
|
|
590
608
|
}
|
|
591
609
|
};
|
|
592
610
|
this.#currentSubscriptionHandler = subscriptionHandler;
|
|
593
611
|
const maxKnownEventNumber = this.#interactionClient.maxKnownEventNumber;
|
|
594
|
-
|
|
612
|
+
await this.#interactionClient.getAllAttributes({
|
|
595
613
|
dataVersionFilters: this.#interactionClient.getCachedClusterDataVersions(),
|
|
596
|
-
executeQueued: !!threadConnected
|
|
614
|
+
executeQueued: !!threadConnected,
|
|
597
615
|
// We queue subscriptions for thread devices
|
|
616
|
+
attributeChangeListener: subscriptionHandler.attributeListener
|
|
598
617
|
});
|
|
599
|
-
await this.#interactionClient.processAttributeUpdates(attributeData, subscriptionHandler.attributeListener);
|
|
600
|
-
attributeData.length = 0;
|
|
601
618
|
const initialSubscriptionData = await this.#interactionClient.subscribeAllAttributesAndEvents({
|
|
602
619
|
isUrgent: true,
|
|
603
620
|
minIntervalFloorSeconds,
|
|
@@ -623,30 +640,33 @@ class PairedNode {
|
|
|
623
640
|
enrichCachedAttributeData: true
|
|
624
641
|
});
|
|
625
642
|
}
|
|
626
|
-
#
|
|
627
|
-
|
|
628
|
-
if (clusterId === import_clusters.DescriptorCluster.id) {
|
|
643
|
+
#checkAttributesForNeededUpdates(endpointId, clusterId, attributeId) {
|
|
644
|
+
if (clusterId === import_clusters.Descriptor.Complete.id) {
|
|
629
645
|
switch (attributeId) {
|
|
630
|
-
case import_clusters.
|
|
631
|
-
case import_clusters.
|
|
632
|
-
case import_clusters.
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
}
|
|
637
|
-
if (!structureUpdateNeeded) {
|
|
638
|
-
switch (attributeId) {
|
|
639
|
-
case import_model.FeatureMap.id:
|
|
640
|
-
case import_model.AttributeList.id:
|
|
641
|
-
case import_model.AcceptedCommandList.id:
|
|
642
|
-
case import_model.ClusterRevision.id:
|
|
643
|
-
structureUpdateNeeded = true;
|
|
644
|
-
break;
|
|
646
|
+
case import_clusters.Descriptor.Complete.attributes.partsList.id:
|
|
647
|
+
case import_clusters.Descriptor.Complete.attributes.serverList.id:
|
|
648
|
+
case import_clusters.Descriptor.Complete.attributes.clientList.id:
|
|
649
|
+
case import_clusters.Descriptor.Complete.attributes.deviceTypeList.id:
|
|
650
|
+
this.#registeredEndpointStructureChanges.set(endpointId, null);
|
|
651
|
+
return;
|
|
645
652
|
}
|
|
653
|
+
} else if (clusterId === import_clusters.BasicInformation.Cluster.id) {
|
|
654
|
+
this.#deviceInformationUpdateNeeded = true;
|
|
646
655
|
}
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
656
|
+
switch (attributeId) {
|
|
657
|
+
case import_model.FeatureMap.id:
|
|
658
|
+
case import_model.AttributeList.id:
|
|
659
|
+
case import_model.AcceptedCommandList.id:
|
|
660
|
+
case import_model.ClusterRevision.id:
|
|
661
|
+
let knownForUpdate = this.#registeredEndpointStructureChanges.get(endpointId);
|
|
662
|
+
if (knownForUpdate !== null) {
|
|
663
|
+
knownForUpdate = knownForUpdate ?? [];
|
|
664
|
+
if (!knownForUpdate.includes(clusterId)) {
|
|
665
|
+
knownForUpdate.push(clusterId);
|
|
666
|
+
this.#registeredEndpointStructureChanges.set(endpointId, knownForUpdate);
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
break;
|
|
650
670
|
}
|
|
651
671
|
}
|
|
652
672
|
#checkEventsForNeededStructureUpdate(_endpointId, clusterId, eventId) {
|
|
@@ -674,55 +694,170 @@ class PairedNode {
|
|
|
674
694
|
this.#reconnectDelayTimer.start();
|
|
675
695
|
}
|
|
676
696
|
async #updateEndpointStructure() {
|
|
677
|
-
const allClusterAttributes =
|
|
697
|
+
const allClusterAttributes = this.#interactionClient.getAllCachedClusterData();
|
|
678
698
|
await this.#initializeEndpointStructure(allClusterAttributes, true);
|
|
679
|
-
this
|
|
680
|
-
|
|
699
|
+
const rootEndpoint = this.getRootEndpoint();
|
|
700
|
+
if (rootEndpoint !== void 0) {
|
|
701
|
+
await this.#nodeDetails.enhanceDeviceDetailsFromCache(rootEndpoint);
|
|
702
|
+
await this.events.deviceInformationChanged.emit(this.#nodeDetails.toStorageData());
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
/**
|
|
706
|
+
* Traverse the structure data and collect all data for the given endpointId.
|
|
707
|
+
* Return true if data for the endpoint was found, otherwise false.
|
|
708
|
+
* If data was found it is added to the collectedData map.
|
|
709
|
+
*/
|
|
710
|
+
collectDescriptorData(structure, endpointId, collectedData) {
|
|
711
|
+
if (collectedData.has(endpointId)) {
|
|
712
|
+
return;
|
|
713
|
+
}
|
|
714
|
+
const endpointData = structure[endpointId];
|
|
715
|
+
const descriptorData = endpointData?.[import_clusters.Descriptor.Complete.id];
|
|
716
|
+
if (endpointData === void 0 || descriptorData === void 0) {
|
|
717
|
+
logger.info(`Descriptor data for endpoint ${endpointId} not found in structure! Ignoring endpoint ...`);
|
|
718
|
+
return;
|
|
719
|
+
}
|
|
720
|
+
collectedData.set(endpointId, descriptorData);
|
|
721
|
+
if (descriptorData.partsList.length) {
|
|
722
|
+
for (const partEndpointId of descriptorData.partsList) {
|
|
723
|
+
this.collectDescriptorData(structure, partEndpointId, collectedData);
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
#hasEndpointChanged(device, descriptorData) {
|
|
728
|
+
return !(areNumberListsSame(
|
|
729
|
+
device.getDeviceTypes().map(({ code }) => code),
|
|
730
|
+
descriptorData.deviceTypeList.map(({ deviceType }) => deviceType)
|
|
731
|
+
) && // Check if the cluster clients are the same - they map to the serverList attribute
|
|
732
|
+
areNumberListsSame(
|
|
733
|
+
device.getAllClusterClients().map(({ id }) => id),
|
|
734
|
+
descriptorData.serverList
|
|
735
|
+
) && // Check if the cluster servers are the same - they map to the clientList attribute
|
|
736
|
+
areNumberListsSame(
|
|
737
|
+
device.getAllClusterServers().map(({ id }) => id),
|
|
738
|
+
descriptorData.clientList
|
|
739
|
+
));
|
|
681
740
|
}
|
|
682
741
|
/** Reads all data from the device and create a device object structure out of it. */
|
|
683
|
-
async #initializeEndpointStructure(allClusterAttributes, updateStructure =
|
|
742
|
+
async #initializeEndpointStructure(allClusterAttributes, updateStructure = this.#localInitializationDone || this.#remoteInitializationDone) {
|
|
743
|
+
if (this.#updateEndpointStructureTimer.isRunning) {
|
|
744
|
+
this.#updateEndpointStructureTimer.stop();
|
|
745
|
+
}
|
|
746
|
+
const eventsToEmit = /* @__PURE__ */ new Map();
|
|
747
|
+
const structureUpdateDetails = this.#registeredEndpointStructureChanges;
|
|
748
|
+
this.#registeredEndpointStructureChanges = /* @__PURE__ */ new Map();
|
|
684
749
|
const allData = (0, import_protocol.structureReadAttributeDataToClusterObject)(allClusterAttributes);
|
|
750
|
+
const descriptors = /* @__PURE__ */ new Map();
|
|
751
|
+
this.collectDescriptorData(allData, (0, import_types.EndpointNumber)(0), descriptors);
|
|
685
752
|
if (updateStructure) {
|
|
686
753
|
const endpointsToRemove = new Set(this.#endpoints.keys());
|
|
687
|
-
for (const
|
|
688
|
-
const
|
|
689
|
-
if (
|
|
690
|
-
|
|
691
|
-
|
|
754
|
+
for (const endpointId of descriptors.keys()) {
|
|
755
|
+
const device = this.#endpoints.get(endpointId);
|
|
756
|
+
if (device !== void 0) {
|
|
757
|
+
const hasChanged = structureUpdateDetails.has(endpointId);
|
|
758
|
+
if (!hasChanged || !this.#hasEndpointChanged(device, descriptors.get(endpointId))) {
|
|
759
|
+
logger.debug(
|
|
760
|
+
`Node ${this.nodeId}: Retaining endpoint`,
|
|
761
|
+
endpointId,
|
|
762
|
+
hasChanged ? "(with only structure changes)" : "(unchanged)"
|
|
763
|
+
);
|
|
764
|
+
endpointsToRemove.delete(endpointId);
|
|
765
|
+
if (hasChanged) {
|
|
766
|
+
eventsToEmit.set(endpointId, "nodeEndpointChanged");
|
|
767
|
+
}
|
|
768
|
+
} else {
|
|
769
|
+
logger.debug(`Node ${this.nodeId}: Recreating endpoint`, endpointId);
|
|
770
|
+
eventsToEmit.set(endpointId, "nodeEndpointChanged");
|
|
771
|
+
}
|
|
692
772
|
}
|
|
693
773
|
}
|
|
694
|
-
for (const
|
|
695
|
-
|
|
696
|
-
this.#endpoints.get(endpointId)
|
|
697
|
-
|
|
774
|
+
for (const endpoint of endpointsToRemove.values()) {
|
|
775
|
+
const endpointId = (0, import_types.EndpointNumber)(endpoint);
|
|
776
|
+
const device = this.#endpoints.get(endpointId);
|
|
777
|
+
if (device !== void 0) {
|
|
778
|
+
if (eventsToEmit.get(endpointId) !== "nodeEndpointChanged") {
|
|
779
|
+
logger.debug(`Node ${this.nodeId}: Removing endpoint`, endpointId);
|
|
780
|
+
eventsToEmit.set(endpointId, "nodeEndpointRemoved");
|
|
781
|
+
}
|
|
782
|
+
device.removeFromStructure();
|
|
783
|
+
this.#endpoints.delete(endpointId);
|
|
784
|
+
}
|
|
698
785
|
}
|
|
699
786
|
} else {
|
|
700
787
|
this.#endpoints.clear();
|
|
701
788
|
}
|
|
702
|
-
const
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
const descriptorData = clusters[import_clusters.DescriptorCluster.id];
|
|
706
|
-
partLists.set(endpointIdNumber, descriptorData.partsList);
|
|
707
|
-
if (this.#endpoints.has(endpointIdNumber)) {
|
|
789
|
+
for (const endpointId of descriptors.keys()) {
|
|
790
|
+
const clusters = allData[endpointId];
|
|
791
|
+
if (this.#endpoints.has(endpointId)) {
|
|
708
792
|
continue;
|
|
709
793
|
}
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
794
|
+
const isRecreation = eventsToEmit.get(endpointId) === "nodeEndpointChanged";
|
|
795
|
+
logger.debug(
|
|
796
|
+
`Node ${this.nodeId}: ${isRecreation ? "Recreating" : "Creating"} endpoint`,
|
|
797
|
+
endpointId,
|
|
798
|
+
import_general.Diagnostic.json(clusters)
|
|
714
799
|
);
|
|
800
|
+
this.#endpoints.set(endpointId, this.#createDevice(endpointId, clusters, this.#interactionClient));
|
|
801
|
+
if (!isRecreation) {
|
|
802
|
+
eventsToEmit.set(endpointId, "nodeEndpointAdded");
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
for (const [endpointId, { partsList }] of descriptors.entries()) {
|
|
806
|
+
const endpoint = this.#endpoints.get(endpointId);
|
|
807
|
+
if (endpoint === void 0) {
|
|
808
|
+
continue;
|
|
809
|
+
}
|
|
810
|
+
endpoint.getChildEndpoints().forEach((child) => {
|
|
811
|
+
if (child.number !== void 0 && !partsList.includes(child.number)) {
|
|
812
|
+
endpoint.removeChildEndpoint(child);
|
|
813
|
+
if (!eventsToEmit.has(endpointId)) {
|
|
814
|
+
eventsToEmit.set(endpointId, "nodeEndpointChanged");
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
});
|
|
818
|
+
}
|
|
819
|
+
this.#structureEndpoints(descriptors);
|
|
820
|
+
if (updateStructure && eventsToEmit.size) {
|
|
821
|
+
for (const [endpointId, eventName] of eventsToEmit.entries()) {
|
|
822
|
+
if (eventName !== "nodeEndpointAdded") {
|
|
823
|
+
const clusterServers = descriptors.get(endpointId)?.serverList;
|
|
824
|
+
await this.#interactionClient.cleanupAttributeData(
|
|
825
|
+
endpointId,
|
|
826
|
+
eventName === "nodeEndpointRemoved" ? void 0 : clusterServers
|
|
827
|
+
);
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
const emitChangeEvents = () => {
|
|
831
|
+
for (const [endpointId, eventName] of eventsToEmit.entries()) {
|
|
832
|
+
logger.debug(`Node ${this.nodeId}: Emitting event ${eventName} for endpoint ${endpointId}`);
|
|
833
|
+
this.events[eventName].emit(endpointId);
|
|
834
|
+
}
|
|
835
|
+
this.#options.stateInformationCallback?.(this.nodeId, 4 /* StructureChanged */);
|
|
836
|
+
this.events.structureChanged.emit();
|
|
837
|
+
};
|
|
838
|
+
if (this.#connectionState === 0 /* Connected */) {
|
|
839
|
+
emitChangeEvents();
|
|
840
|
+
} else {
|
|
841
|
+
this.events.stateChanged.once((State) => {
|
|
842
|
+
if (State === 0 /* Connected */) {
|
|
843
|
+
emitChangeEvents();
|
|
844
|
+
}
|
|
845
|
+
});
|
|
846
|
+
}
|
|
715
847
|
}
|
|
716
|
-
this.#structureEndpoints(partLists);
|
|
717
848
|
}
|
|
718
|
-
/**
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
849
|
+
/**
|
|
850
|
+
* Bring the endpoints in a structure based on their partsList attribute. This method only adds endpoints into the
|
|
851
|
+
* right place as children, Cleanup is not happening here
|
|
852
|
+
*/
|
|
853
|
+
#structureEndpoints(descriptors) {
|
|
854
|
+
const partLists = Array.from(descriptors.entries()).map(
|
|
855
|
+
([ep, { partsList }]) => [ep, partsList]
|
|
856
|
+
// else Typescript gets confused
|
|
723
857
|
);
|
|
858
|
+
logger.debug(`Node ${this.nodeId}: Endpoints from PartsLists`, import_general.Diagnostic.json(partLists));
|
|
724
859
|
const endpointUsages = {};
|
|
725
|
-
|
|
860
|
+
partLists.forEach(
|
|
726
861
|
([parent, partsList]) => partsList.forEach((endPoint) => {
|
|
727
862
|
if (endPoint === parent) {
|
|
728
863
|
logger.warn(`Node ${this.nodeId}: Endpoint ${endPoint} is referencing itself!`);
|
|
@@ -746,14 +881,18 @@ class PairedNode {
|
|
|
746
881
|
const childEndpointId = (0, import_types.EndpointNumber)(parseInt(childId));
|
|
747
882
|
const childEndpoint = this.#endpoints.get(childEndpointId);
|
|
748
883
|
const parentEndpoint = this.#endpoints.get(usages[0]);
|
|
884
|
+
const existingChildEndpoint = parentEndpoint?.getChildEndpoint(childEndpointId);
|
|
749
885
|
if (childEndpoint === void 0 || parentEndpoint === void 0) {
|
|
750
886
|
logger.warn(
|
|
751
887
|
`Node ${this.nodeId}: Endpoint ${usages[0]} not found in the data received from the device!`
|
|
752
888
|
);
|
|
753
|
-
} else if (
|
|
889
|
+
} else if (existingChildEndpoint !== childEndpoint) {
|
|
754
890
|
logger.debug(
|
|
755
891
|
`Node ${this.nodeId}: Endpoint structure: Child: ${childEndpointId} -> Parent: ${parentEndpoint.number}`
|
|
756
892
|
);
|
|
893
|
+
if (existingChildEndpoint !== void 0) {
|
|
894
|
+
parentEndpoint.removeChildEndpoint(existingChildEndpoint);
|
|
895
|
+
}
|
|
757
896
|
parentEndpoint.addChildEndpoint(childEndpoint);
|
|
758
897
|
}
|
|
759
898
|
delete endpointUsages[(0, import_types.EndpointNumber)(parseInt(childId))];
|
|
@@ -775,7 +914,7 @@ class PairedNode {
|
|
|
775
914
|
}
|
|
776
915
|
/** Create a device object from the data read from the device. */
|
|
777
916
|
#createDevice(endpointId, data, interactionClient) {
|
|
778
|
-
const descriptorData = data[import_clusters.
|
|
917
|
+
const descriptorData = data[import_clusters.Descriptor.Complete.id];
|
|
779
918
|
const deviceTypes = descriptorData.deviceTypeList.flatMap(({ deviceType, revision }) => {
|
|
780
919
|
const deviceTypeDefinition = (0, import_DeviceTypes.getDeviceTypeDefinitionFromModelByCode)(deviceType);
|
|
781
920
|
if (deviceTypeDefinition === void 0) {
|