@matter/protocol 0.15.3 → 0.15.5
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/action/client/ReadScope.d.ts +4 -0
- package/dist/cjs/action/client/ReadScope.d.ts.map +1 -1
- package/dist/cjs/action/client/ReadScope.js +2 -1
- package/dist/cjs/action/client/ReadScope.js.map +1 -1
- package/dist/cjs/fabric/Fabric.d.ts.map +1 -1
- package/dist/cjs/fabric/Fabric.js.map +1 -1
- package/dist/cjs/fabric/FabricAuthority.d.ts +0 -1
- package/dist/cjs/fabric/FabricAuthority.d.ts.map +1 -1
- package/dist/cjs/fabric/FabricAuthority.js +2 -3
- package/dist/cjs/fabric/FabricAuthority.js.map +1 -1
- package/dist/cjs/fabric/TestFabric.d.ts.map +1 -1
- package/dist/cjs/fabric/TestFabric.js +2 -1
- package/dist/cjs/fabric/TestFabric.js.map +1 -1
- package/dist/cjs/interaction/AttributeDataDecoder.d.ts +9 -7
- package/dist/cjs/interaction/AttributeDataDecoder.d.ts.map +1 -1
- package/dist/cjs/interaction/AttributeDataDecoder.js.map +1 -1
- package/dist/cjs/interaction/DecodedDataReport.d.ts +1 -0
- package/dist/cjs/interaction/DecodedDataReport.d.ts.map +1 -1
- package/dist/cjs/interaction/DecodedDataReport.js.map +1 -1
- package/dist/cjs/interaction/InteractionClient.d.ts +15 -5
- package/dist/cjs/interaction/InteractionClient.d.ts.map +1 -1
- package/dist/cjs/interaction/InteractionClient.js +117 -102
- package/dist/cjs/interaction/InteractionClient.js.map +1 -1
- package/dist/cjs/interaction/InteractionMessenger.d.ts +10 -90
- package/dist/cjs/interaction/InteractionMessenger.d.ts.map +1 -1
- package/dist/cjs/interaction/InteractionMessenger.js +98 -22
- package/dist/cjs/interaction/InteractionMessenger.js.map +2 -2
- package/dist/cjs/interaction/SubscriptionClient.d.ts +2 -2
- package/dist/cjs/interaction/SubscriptionClient.d.ts.map +1 -1
- package/dist/cjs/interaction/SubscriptionClient.js +1 -1
- package/dist/cjs/interaction/SubscriptionClient.js.map +1 -1
- package/dist/cjs/mdns/MdnsScanner.d.ts.map +1 -1
- package/dist/cjs/mdns/MdnsScanner.js +1 -2
- package/dist/cjs/mdns/MdnsScanner.js.map +1 -1
- package/dist/cjs/mdns/MdnsServer.js +1 -1
- package/dist/cjs/mdns/MdnsServer.js.map +1 -1
- package/dist/cjs/peer/PeerAddressStore.d.ts +3 -1
- package/dist/cjs/peer/PeerAddressStore.d.ts.map +1 -1
- package/dist/cjs/peer/PeerAddressStore.js.map +1 -1
- package/dist/cjs/session/SessionManager.d.ts.map +1 -1
- package/dist/cjs/session/SessionManager.js +17 -9
- package/dist/cjs/session/SessionManager.js.map +1 -1
- package/dist/cjs/session/pase/PaseServer.d.ts.map +1 -1
- package/dist/cjs/session/pase/PaseServer.js +2 -1
- package/dist/cjs/session/pase/PaseServer.js.map +1 -1
- package/dist/esm/action/client/ReadScope.d.ts +4 -0
- package/dist/esm/action/client/ReadScope.d.ts.map +1 -1
- package/dist/esm/action/client/ReadScope.js +2 -1
- package/dist/esm/action/client/ReadScope.js.map +1 -1
- package/dist/esm/fabric/Fabric.d.ts.map +1 -1
- package/dist/esm/fabric/Fabric.js.map +1 -1
- package/dist/esm/fabric/FabricAuthority.d.ts +0 -1
- package/dist/esm/fabric/FabricAuthority.d.ts.map +1 -1
- package/dist/esm/fabric/FabricAuthority.js +2 -3
- package/dist/esm/fabric/FabricAuthority.js.map +1 -1
- package/dist/esm/fabric/TestFabric.d.ts.map +1 -1
- package/dist/esm/fabric/TestFabric.js +3 -2
- package/dist/esm/fabric/TestFabric.js.map +1 -1
- package/dist/esm/interaction/AttributeDataDecoder.d.ts +9 -7
- package/dist/esm/interaction/AttributeDataDecoder.d.ts.map +1 -1
- package/dist/esm/interaction/AttributeDataDecoder.js.map +1 -1
- package/dist/esm/interaction/DecodedDataReport.d.ts +1 -0
- package/dist/esm/interaction/DecodedDataReport.d.ts.map +1 -1
- package/dist/esm/interaction/DecodedDataReport.js.map +1 -1
- package/dist/esm/interaction/InteractionClient.d.ts +15 -5
- package/dist/esm/interaction/InteractionClient.d.ts.map +1 -1
- package/dist/esm/interaction/InteractionClient.js +119 -103
- package/dist/esm/interaction/InteractionClient.js.map +1 -1
- package/dist/esm/interaction/InteractionMessenger.d.ts +10 -90
- package/dist/esm/interaction/InteractionMessenger.d.ts.map +1 -1
- package/dist/esm/interaction/InteractionMessenger.js +98 -22
- package/dist/esm/interaction/InteractionMessenger.js.map +2 -2
- package/dist/esm/interaction/SubscriptionClient.d.ts +2 -2
- package/dist/esm/interaction/SubscriptionClient.d.ts.map +1 -1
- package/dist/esm/interaction/SubscriptionClient.js +1 -1
- package/dist/esm/interaction/SubscriptionClient.js.map +1 -1
- package/dist/esm/mdns/MdnsScanner.d.ts.map +1 -1
- package/dist/esm/mdns/MdnsScanner.js +1 -2
- package/dist/esm/mdns/MdnsScanner.js.map +1 -1
- package/dist/esm/mdns/MdnsServer.js +1 -1
- package/dist/esm/mdns/MdnsServer.js.map +1 -1
- package/dist/esm/peer/PeerAddressStore.d.ts +3 -1
- package/dist/esm/peer/PeerAddressStore.d.ts.map +1 -1
- package/dist/esm/peer/PeerAddressStore.js.map +1 -1
- package/dist/esm/session/SessionManager.d.ts.map +1 -1
- package/dist/esm/session/SessionManager.js +19 -10
- package/dist/esm/session/SessionManager.js.map +1 -1
- package/dist/esm/session/pase/PaseServer.d.ts.map +1 -1
- package/dist/esm/session/pase/PaseServer.js +2 -1
- package/dist/esm/session/pase/PaseServer.js.map +1 -1
- package/package.json +6 -6
- package/src/action/client/ReadScope.ts +7 -0
- package/src/fabric/Fabric.ts +1 -1
- package/src/fabric/FabricAuthority.ts +2 -2
- package/src/fabric/TestFabric.ts +2 -1
- package/src/interaction/AttributeDataDecoder.ts +4 -1
- package/src/interaction/DecodedDataReport.ts +1 -0
- package/src/interaction/InteractionClient.ts +183 -122
- package/src/interaction/InteractionMessenger.ts +126 -22
- package/src/interaction/SubscriptionClient.ts +6 -5
- package/src/mdns/MdnsScanner.ts +1 -2
- package/src/mdns/MdnsServer.ts +2 -2
- package/src/peer/PeerAddressStore.ts +3 -1
- package/src/session/SessionManager.ts +35 -24
- package/src/session/pase/PaseServer.ts +2 -1
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
import { ReadScope } from "#action/client/ReadScope.js";
|
|
7
8
|
import { AccessControl } from "#clusters/access-control";
|
|
8
9
|
import {
|
|
9
10
|
Diagnostic,
|
|
@@ -12,11 +13,13 @@ import {
|
|
|
12
13
|
ImplementationError,
|
|
13
14
|
Logger,
|
|
14
15
|
MatterFlowError,
|
|
16
|
+
MaybePromise,
|
|
15
17
|
PromiseQueue,
|
|
16
18
|
ServerAddressIp,
|
|
17
19
|
Timer,
|
|
18
20
|
UnexpectedDataError,
|
|
19
21
|
isDeepEqual,
|
|
22
|
+
serialize,
|
|
20
23
|
} from "#general";
|
|
21
24
|
import { Specification } from "#model";
|
|
22
25
|
import { PeerAddress, PeerAddressMap } from "#peer/PeerAddress.js";
|
|
@@ -40,6 +43,7 @@ import {
|
|
|
40
43
|
ResponseType,
|
|
41
44
|
StatusCode,
|
|
42
45
|
StatusResponseError,
|
|
46
|
+
SubscribeRequest,
|
|
43
47
|
TlvEventFilter,
|
|
44
48
|
TlvInvokeResponse,
|
|
45
49
|
TlvNoResponse,
|
|
@@ -55,7 +59,7 @@ import { MessageChannel } from "../protocol/MessageChannel.js";
|
|
|
55
59
|
import { DecodedAttributeReportStatus, DecodedAttributeReportValue } from "./AttributeDataDecoder.js";
|
|
56
60
|
import { DecodedDataReport } from "./DecodedDataReport.js";
|
|
57
61
|
import { DecodedEventData, DecodedEventReportStatus, DecodedEventReportValue } from "./EventDataDecoder.js";
|
|
58
|
-
import {
|
|
62
|
+
import { InteractionClientMessenger, ReadRequest } from "./InteractionMessenger.js";
|
|
59
63
|
import { RegisteredSubscription, SubscriptionClient } from "./SubscriptionClient.js";
|
|
60
64
|
|
|
61
65
|
const logger = Logger.get("InteractionClient");
|
|
@@ -219,6 +223,11 @@ export class InteractionClient {
|
|
|
219
223
|
enrichCachedAttributeData?: boolean;
|
|
220
224
|
isFabricFiltered?: boolean;
|
|
221
225
|
executeQueued?: boolean;
|
|
226
|
+
attributeChangeListener?: (
|
|
227
|
+
data: DecodedAttributeReportValue<any>,
|
|
228
|
+
valueChanged?: boolean,
|
|
229
|
+
oldValue?: any,
|
|
230
|
+
) => void;
|
|
222
231
|
} = {},
|
|
223
232
|
): Promise<DecodedAttributeReportValue<any>[]> {
|
|
224
233
|
return (
|
|
@@ -255,6 +264,11 @@ export class InteractionClient {
|
|
|
255
264
|
eventFilters?: TypeFromSchema<typeof TlvEventFilter>[];
|
|
256
265
|
isFabricFiltered?: boolean;
|
|
257
266
|
executeQueued?: boolean;
|
|
267
|
+
attributeChangeListener?: (
|
|
268
|
+
data: DecodedAttributeReportValue<any>,
|
|
269
|
+
valueChanged?: boolean,
|
|
270
|
+
oldValue?: any,
|
|
271
|
+
) => void;
|
|
258
272
|
} = {},
|
|
259
273
|
): Promise<{
|
|
260
274
|
attributeReports: DecodedAttributeReportValue<any>[];
|
|
@@ -274,6 +288,11 @@ export class InteractionClient {
|
|
|
274
288
|
enrichCachedAttributeData?: boolean;
|
|
275
289
|
isFabricFiltered?: boolean;
|
|
276
290
|
executeQueued?: boolean;
|
|
291
|
+
attributeChangeListener?: (
|
|
292
|
+
data: DecodedAttributeReportValue<any>,
|
|
293
|
+
valueChanged?: boolean,
|
|
294
|
+
oldValue?: any,
|
|
295
|
+
) => void;
|
|
277
296
|
} = {},
|
|
278
297
|
): Promise<DecodedAttributeReportValue<any>[]> {
|
|
279
298
|
return (await this.getMultipleAttributesAndEvents(options)).attributeReports;
|
|
@@ -286,6 +305,11 @@ export class InteractionClient {
|
|
|
286
305
|
enrichCachedAttributeData?: boolean;
|
|
287
306
|
isFabricFiltered?: boolean;
|
|
288
307
|
executeQueued?: boolean;
|
|
308
|
+
attributeChangeListener?: (
|
|
309
|
+
data: DecodedAttributeReportValue<any>,
|
|
310
|
+
valueChanged?: boolean,
|
|
311
|
+
oldValue?: any,
|
|
312
|
+
) => void;
|
|
289
313
|
} = {},
|
|
290
314
|
): Promise<{
|
|
291
315
|
attributeData: DecodedAttributeReportValue<any>[];
|
|
@@ -327,6 +351,11 @@ export class InteractionClient {
|
|
|
327
351
|
eventFilters?: TypeFromSchema<typeof TlvEventFilter>[];
|
|
328
352
|
isFabricFiltered?: boolean;
|
|
329
353
|
executeQueued?: boolean;
|
|
354
|
+
attributeChangeListener?: (
|
|
355
|
+
data: DecodedAttributeReportValue<any>,
|
|
356
|
+
valueChanged?: boolean,
|
|
357
|
+
oldValue?: any,
|
|
358
|
+
) => void;
|
|
330
359
|
} = {},
|
|
331
360
|
): Promise<DecodedDataReport> {
|
|
332
361
|
if (this.isGroupAddress) {
|
|
@@ -340,6 +369,8 @@ export class InteractionClient {
|
|
|
340
369
|
events: eventRequests,
|
|
341
370
|
enrichCachedAttributeData,
|
|
342
371
|
eventFilters,
|
|
372
|
+
isFabricFiltered = true,
|
|
373
|
+
attributeChangeListener,
|
|
343
374
|
} = options;
|
|
344
375
|
if (attributeRequests === undefined && eventRequests === undefined) {
|
|
345
376
|
throw new ImplementationError("When reading attributes and events, at least one must be specified.");
|
|
@@ -373,18 +404,21 @@ export class InteractionClient {
|
|
|
373
404
|
}
|
|
374
405
|
|
|
375
406
|
const result = await this.withMessenger(async messenger => {
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
407
|
+
return await this.processReadRequest(
|
|
408
|
+
messenger,
|
|
409
|
+
{
|
|
410
|
+
attributeRequests,
|
|
411
|
+
dataVersionFilters: dataVersionFilters?.map(({ endpointId, clusterId, dataVersion }) => ({
|
|
412
|
+
path: { endpointId, clusterId },
|
|
413
|
+
dataVersion,
|
|
414
|
+
})),
|
|
415
|
+
eventRequests,
|
|
416
|
+
eventFilters,
|
|
417
|
+
isFabricFiltered,
|
|
418
|
+
interactionModelRevision: Specification.INTERACTION_MODEL_REVISION,
|
|
419
|
+
},
|
|
420
|
+
attributeChangeListener,
|
|
421
|
+
);
|
|
388
422
|
}, executeQueued);
|
|
389
423
|
|
|
390
424
|
if (dataVersionFilters !== undefined && dataVersionFilters.length > 0 && enrichCachedAttributeData) {
|
|
@@ -401,6 +435,11 @@ export class InteractionClient {
|
|
|
401
435
|
isFabricFiltered?: boolean;
|
|
402
436
|
requestFromRemote?: boolean;
|
|
403
437
|
executeQueued?: boolean;
|
|
438
|
+
attributeChangeListener?: (
|
|
439
|
+
data: DecodedAttributeReportValue<any>,
|
|
440
|
+
valueChanged?: boolean,
|
|
441
|
+
oldValue?: any,
|
|
442
|
+
) => void;
|
|
404
443
|
}): Promise<AttributeJsType<A> | undefined> {
|
|
405
444
|
const { requestFromRemote } = options;
|
|
406
445
|
const response = await this.getAttributeWithVersion({
|
|
@@ -445,12 +484,25 @@ export class InteractionClient {
|
|
|
445
484
|
isFabricFiltered?: boolean;
|
|
446
485
|
requestFromRemote?: boolean;
|
|
447
486
|
executeQueued?: boolean;
|
|
487
|
+
attributeChangeListener?: (
|
|
488
|
+
data: DecodedAttributeReportValue<any>,
|
|
489
|
+
valueChanged?: boolean,
|
|
490
|
+
oldValue?: any,
|
|
491
|
+
) => void;
|
|
448
492
|
}): Promise<{ value: AttributeJsType<A>; version: number } | undefined> {
|
|
449
493
|
if (this.isGroupAddress) {
|
|
450
494
|
throw new ImplementationError("Reading data from group addresses is not supported.");
|
|
451
495
|
}
|
|
452
496
|
|
|
453
|
-
const {
|
|
497
|
+
const {
|
|
498
|
+
endpointId,
|
|
499
|
+
clusterId,
|
|
500
|
+
attribute,
|
|
501
|
+
requestFromRemote,
|
|
502
|
+
isFabricFiltered,
|
|
503
|
+
executeQueued,
|
|
504
|
+
attributeChangeListener,
|
|
505
|
+
} = options;
|
|
454
506
|
const { id: attributeId } = attribute;
|
|
455
507
|
if (this.#nodeStore !== undefined) {
|
|
456
508
|
if (!requestFromRemote) {
|
|
@@ -468,6 +520,7 @@ export class InteractionClient {
|
|
|
468
520
|
attributes: [{ endpointId, clusterId, attributeId }],
|
|
469
521
|
isFabricFiltered,
|
|
470
522
|
executeQueued,
|
|
523
|
+
attributeChangeListener,
|
|
471
524
|
});
|
|
472
525
|
|
|
473
526
|
if (attributeReports.length === 0) {
|
|
@@ -501,6 +554,11 @@ export class InteractionClient {
|
|
|
501
554
|
private async processReadRequest(
|
|
502
555
|
messenger: InteractionClientMessenger,
|
|
503
556
|
request: ReadRequest,
|
|
557
|
+
attributeChangeListener?: (
|
|
558
|
+
data: DecodedAttributeReportValue<any>,
|
|
559
|
+
valueChanged?: boolean,
|
|
560
|
+
oldValue?: any,
|
|
561
|
+
) => void,
|
|
504
562
|
): Promise<DecodedDataReport> {
|
|
505
563
|
const { attributeRequests, eventRequests } = request;
|
|
506
564
|
logger.debug(
|
|
@@ -510,15 +568,19 @@ export class InteractionClient {
|
|
|
510
568
|
);
|
|
511
569
|
// Send read request and combine all (potentially chunked) responses
|
|
512
570
|
await messenger.sendReadRequest(request);
|
|
513
|
-
const
|
|
571
|
+
const scope = ReadScope(request);
|
|
572
|
+
const response = await messenger.readAggregateDataReport(chunk =>
|
|
573
|
+
this.processAttributeUpdates(scope, chunk, attributeChangeListener),
|
|
574
|
+
);
|
|
514
575
|
|
|
515
576
|
// Normalize and decode the response
|
|
516
|
-
const
|
|
517
|
-
const { attributeReports, attributeStatus, eventReports, eventStatus } = normalizedResult;
|
|
577
|
+
const { attributeReports, attributeStatus, eventReports, eventStatus } = response;
|
|
518
578
|
|
|
519
579
|
const logData = Array<string>();
|
|
520
580
|
if (attributeReports.length > 0) {
|
|
521
|
-
logData.push(
|
|
581
|
+
logData.push(
|
|
582
|
+
`attributes ${attributeReports.map(({ path, value }) => `${resolveAttributeName(path)}=${serialize(value)}`).join(", ")}`,
|
|
583
|
+
);
|
|
522
584
|
}
|
|
523
585
|
if (eventReports.length > 0) {
|
|
524
586
|
logData.push(`events ${eventReports.map(({ path }) => resolveEventName(path)).join(", ")}`);
|
|
@@ -532,7 +594,7 @@ export class InteractionClient {
|
|
|
532
594
|
logger.debug(
|
|
533
595
|
logData.length ? `Received read response with ${logData.join(", ")}` : "Received empty read response",
|
|
534
596
|
);
|
|
535
|
-
return
|
|
597
|
+
return response;
|
|
536
598
|
}
|
|
537
599
|
|
|
538
600
|
async setAttribute<T>(options: {
|
|
@@ -744,27 +806,30 @@ export class InteractionClient {
|
|
|
744
806
|
})}${knownDataVersion !== undefined ? ` (knownDataVersion=${knownDataVersion})` : ""} with minInterval=${minIntervalFloorSeconds}s/maxInterval=${maxIntervalCeilingSeconds}s`,
|
|
745
807
|
);
|
|
746
808
|
|
|
809
|
+
const request: SubscribeRequest = {
|
|
810
|
+
interactionModelRevision: Specification.INTERACTION_MODEL_REVISION,
|
|
811
|
+
attributeRequests: [{ endpointId, clusterId, attributeId }],
|
|
812
|
+
dataVersionFilters:
|
|
813
|
+
knownDataVersion !== undefined
|
|
814
|
+
? [{ path: { endpointId, clusterId }, dataVersion: knownDataVersion }]
|
|
815
|
+
: undefined,
|
|
816
|
+
keepSubscriptions,
|
|
817
|
+
minIntervalFloorSeconds,
|
|
818
|
+
maxIntervalCeilingSeconds,
|
|
819
|
+
isFabricFiltered,
|
|
820
|
+
};
|
|
821
|
+
const scope = ReadScope(request);
|
|
822
|
+
|
|
747
823
|
const {
|
|
748
824
|
subscribeResponse: { subscriptionId, maxInterval },
|
|
749
825
|
report,
|
|
750
826
|
maximumPeerResponseTimeMs,
|
|
751
827
|
} = await this.withMessenger<{
|
|
752
828
|
subscribeResponse: TypeFromSchema<typeof TlvSubscribeResponse>;
|
|
753
|
-
report:
|
|
829
|
+
report: DecodedDataReport;
|
|
754
830
|
maximumPeerResponseTimeMs: number;
|
|
755
831
|
}>(async messenger => {
|
|
756
|
-
await messenger.sendSubscribeRequest(
|
|
757
|
-
interactionModelRevision: Specification.INTERACTION_MODEL_REVISION,
|
|
758
|
-
attributeRequests: [{ endpointId, clusterId, attributeId }],
|
|
759
|
-
dataVersionFilters:
|
|
760
|
-
knownDataVersion !== undefined
|
|
761
|
-
? [{ path: { endpointId, clusterId }, dataVersion: knownDataVersion }]
|
|
762
|
-
: undefined,
|
|
763
|
-
keepSubscriptions,
|
|
764
|
-
minIntervalFloorSeconds,
|
|
765
|
-
maxIntervalCeilingSeconds,
|
|
766
|
-
isFabricFiltered,
|
|
767
|
-
});
|
|
832
|
+
await messenger.sendSubscribeRequest(request);
|
|
768
833
|
const { subscribeResponse, report } = await messenger.readAggregateSubscribeResponse();
|
|
769
834
|
return {
|
|
770
835
|
subscribeResponse,
|
|
@@ -773,14 +838,8 @@ export class InteractionClient {
|
|
|
773
838
|
};
|
|
774
839
|
}, executeQueued);
|
|
775
840
|
|
|
776
|
-
const subscriptionListener = async (dataReport:
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
if (!Array.isArray(dataReport.attributeReports) || !dataReport.attributeReports.length) {
|
|
780
|
-
return;
|
|
781
|
-
}
|
|
782
|
-
|
|
783
|
-
const { attributeReports } = DecodedDataReport(dataReport);
|
|
841
|
+
const subscriptionListener = async (dataReport: DecodedDataReport) => {
|
|
842
|
+
const { attributeReports } = dataReport;
|
|
784
843
|
|
|
785
844
|
if (attributeReports.length === 0) {
|
|
786
845
|
throw new MatterFlowError("Subscription result reporting undefined/no value not specified");
|
|
@@ -792,9 +851,11 @@ export class InteractionClient {
|
|
|
792
851
|
if (value === undefined)
|
|
793
852
|
throw new MatterFlowError("Subscription result reporting undefined value not specified.");
|
|
794
853
|
|
|
795
|
-
await this.#nodeStore?.persistAttributes(
|
|
854
|
+
await this.#nodeStore?.persistAttributes(attributeReports, scope);
|
|
796
855
|
|
|
797
856
|
listener?.(value, version);
|
|
857
|
+
|
|
858
|
+
updateReceived?.();
|
|
798
859
|
};
|
|
799
860
|
|
|
800
861
|
await this.#registerSubscription(
|
|
@@ -811,7 +872,7 @@ export class InteractionClient {
|
|
|
811
872
|
return { maxInterval };
|
|
812
873
|
}
|
|
813
874
|
|
|
814
|
-
async #registerSubscription(subscription: RegisteredSubscription, initialReport:
|
|
875
|
+
async #registerSubscription(subscription: RegisteredSubscription, initialReport: DecodedDataReport) {
|
|
815
876
|
this.#ownSubscriptionIds.add(subscription.id);
|
|
816
877
|
this.#subscriptionClient.add(subscription);
|
|
817
878
|
await subscription.onData(initialReport);
|
|
@@ -862,7 +923,7 @@ export class InteractionClient {
|
|
|
862
923
|
maximumPeerResponseTimeMs,
|
|
863
924
|
} = await this.withMessenger<{
|
|
864
925
|
subscribeResponse: TypeFromSchema<typeof TlvSubscribeResponse>;
|
|
865
|
-
report:
|
|
926
|
+
report: DecodedDataReport;
|
|
866
927
|
maximumPeerResponseTimeMs: number;
|
|
867
928
|
}>(async messenger => {
|
|
868
929
|
await messenger.sendSubscribeRequest({
|
|
@@ -882,14 +943,8 @@ export class InteractionClient {
|
|
|
882
943
|
};
|
|
883
944
|
}, executeQueued);
|
|
884
945
|
|
|
885
|
-
const subscriptionListener = (dataReport:
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
if (!Array.isArray(dataReport.eventReports) || !dataReport.eventReports.length) {
|
|
889
|
-
return;
|
|
890
|
-
}
|
|
891
|
-
|
|
892
|
-
const { eventReports } = DecodedDataReport(dataReport);
|
|
946
|
+
const subscriptionListener = (dataReport: DecodedDataReport) => {
|
|
947
|
+
const { eventReports } = dataReport;
|
|
893
948
|
|
|
894
949
|
if (eventReports.length === 0) {
|
|
895
950
|
throw new MatterFlowError("Received empty subscription result value.");
|
|
@@ -902,7 +957,10 @@ export class InteractionClient {
|
|
|
902
957
|
throw new MatterFlowError("Subscription result reporting undefined value not specified.");
|
|
903
958
|
|
|
904
959
|
events.forEach(event => listener?.(event));
|
|
960
|
+
|
|
961
|
+
updateReceived?.();
|
|
905
962
|
};
|
|
963
|
+
|
|
906
964
|
await this.#registerSubscription(
|
|
907
965
|
{
|
|
908
966
|
id: subscriptionId,
|
|
@@ -1024,30 +1082,36 @@ export class InteractionClient {
|
|
|
1024
1082
|
);
|
|
1025
1083
|
}
|
|
1026
1084
|
|
|
1085
|
+
const request: SubscribeRequest = {
|
|
1086
|
+
interactionModelRevision: Specification.INTERACTION_MODEL_REVISION,
|
|
1087
|
+
attributeRequests,
|
|
1088
|
+
eventRequests,
|
|
1089
|
+
keepSubscriptions,
|
|
1090
|
+
minIntervalFloorSeconds,
|
|
1091
|
+
maxIntervalCeilingSeconds,
|
|
1092
|
+
isFabricFiltered,
|
|
1093
|
+
eventFilters,
|
|
1094
|
+
dataVersionFilters: dataVersionFilters?.map(({ endpointId, clusterId, dataVersion }) => ({
|
|
1095
|
+
path: { endpointId, clusterId },
|
|
1096
|
+
dataVersion,
|
|
1097
|
+
})),
|
|
1098
|
+
};
|
|
1099
|
+
const scope = ReadScope(request);
|
|
1100
|
+
|
|
1101
|
+
let processNewAttributeChangesInListener = false;
|
|
1027
1102
|
const {
|
|
1028
1103
|
report,
|
|
1029
1104
|
subscribeResponse: { subscriptionId, maxInterval },
|
|
1030
1105
|
maximumPeerResponseTimeMs,
|
|
1031
1106
|
} = await this.withMessenger<{
|
|
1032
1107
|
subscribeResponse: TypeFromSchema<typeof TlvSubscribeResponse>;
|
|
1033
|
-
report:
|
|
1108
|
+
report: DecodedDataReport;
|
|
1034
1109
|
maximumPeerResponseTimeMs: number;
|
|
1035
1110
|
}>(async messenger => {
|
|
1036
|
-
await messenger.sendSubscribeRequest(
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
keepSubscriptions,
|
|
1041
|
-
minIntervalFloorSeconds,
|
|
1042
|
-
maxIntervalCeilingSeconds,
|
|
1043
|
-
isFabricFiltered,
|
|
1044
|
-
eventFilters,
|
|
1045
|
-
dataVersionFilters: dataVersionFilters?.map(({ endpointId, clusterId, dataVersion }) => ({
|
|
1046
|
-
path: { endpointId, clusterId },
|
|
1047
|
-
dataVersion,
|
|
1048
|
-
})),
|
|
1049
|
-
});
|
|
1050
|
-
const { subscribeResponse, report } = await messenger.readAggregateSubscribeResponse();
|
|
1111
|
+
await messenger.sendSubscribeRequest(request);
|
|
1112
|
+
const { subscribeResponse, report } = await messenger.readAggregateSubscribeResponse(attributeReports =>
|
|
1113
|
+
this.processAttributeUpdates(scope, attributeReports, attributeListener),
|
|
1114
|
+
);
|
|
1051
1115
|
return {
|
|
1052
1116
|
subscribeResponse,
|
|
1053
1117
|
report,
|
|
@@ -1092,59 +1156,71 @@ export class InteractionClient {
|
|
|
1092
1156
|
await this.#nodeStore?.updateLastEventNumber(maxEventNumber);
|
|
1093
1157
|
}
|
|
1094
1158
|
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
path: { endpointId, clusterId, attributeId },
|
|
1099
|
-
value,
|
|
1100
|
-
version,
|
|
1101
|
-
} = data;
|
|
1102
|
-
logger.debug(
|
|
1103
|
-
`Received attribute update: ${resolveAttributeName({
|
|
1104
|
-
endpointId,
|
|
1105
|
-
clusterId,
|
|
1106
|
-
attributeId,
|
|
1107
|
-
})} = ${Diagnostic.json(value)} (version=${version})`,
|
|
1108
|
-
);
|
|
1109
|
-
if (value === undefined) throw new MatterFlowError("Received empty subscription result value.");
|
|
1110
|
-
const { value: oldValue } =
|
|
1111
|
-
this.#nodeStore?.retrieveAttribute(endpointId, clusterId, attributeId) ?? {};
|
|
1112
|
-
const changed = oldValue !== undefined ? !isDeepEqual(oldValue, value) : undefined;
|
|
1113
|
-
if (changed !== false) {
|
|
1114
|
-
await this.#nodeStore?.persistAttributes([data]);
|
|
1115
|
-
}
|
|
1116
|
-
|
|
1117
|
-
attributeListener?.(data, changed, oldValue);
|
|
1118
|
-
}
|
|
1159
|
+
// Initial Data reports during seeding are handled directly
|
|
1160
|
+
if (processNewAttributeChangesInListener && attributeReports !== undefined) {
|
|
1161
|
+
await this.processAttributeUpdates(scope, attributeReports, attributeListener);
|
|
1119
1162
|
}
|
|
1120
1163
|
updateReceived?.();
|
|
1121
1164
|
};
|
|
1122
1165
|
|
|
1123
|
-
const seedReport = DecodedDataReport(report);
|
|
1124
|
-
|
|
1125
1166
|
await this.#registerSubscription(
|
|
1126
1167
|
{
|
|
1127
1168
|
id: subscriptionId,
|
|
1128
1169
|
maximumPeerResponseTimeMs,
|
|
1129
1170
|
maxIntervalS: maxInterval,
|
|
1130
1171
|
|
|
1131
|
-
onData: dataReport => subscriptionListener(
|
|
1172
|
+
onData: dataReport => subscriptionListener(dataReport),
|
|
1132
1173
|
|
|
1133
1174
|
onTimeout: updateTimeoutHandler,
|
|
1134
1175
|
},
|
|
1135
|
-
|
|
1176
|
+
report,
|
|
1136
1177
|
);
|
|
1178
|
+
processNewAttributeChangesInListener = true;
|
|
1137
1179
|
|
|
1138
1180
|
if (dataVersionFilters !== undefined && dataVersionFilters.length > 0 && enrichCachedAttributeData) {
|
|
1139
|
-
this.#enrichCachedAttributeData(
|
|
1181
|
+
this.#enrichCachedAttributeData(report.attributeReports, dataVersionFilters);
|
|
1140
1182
|
}
|
|
1141
1183
|
|
|
1142
1184
|
return {
|
|
1143
|
-
...
|
|
1185
|
+
...report,
|
|
1144
1186
|
maxInterval,
|
|
1145
1187
|
};
|
|
1146
1188
|
}
|
|
1147
1189
|
|
|
1190
|
+
/**
|
|
1191
|
+
* Process changed attributes, detect changes and persist them to the node store
|
|
1192
|
+
*/
|
|
1193
|
+
async processAttributeUpdates(
|
|
1194
|
+
scope: ReadScope,
|
|
1195
|
+
attributeReports: DecodedAttributeReportValue<any>[],
|
|
1196
|
+
attributeListener?: (data: DecodedAttributeReportValue<any>, valueChanged?: boolean, oldValue?: any) => void,
|
|
1197
|
+
) {
|
|
1198
|
+
for (const data of attributeReports) {
|
|
1199
|
+
const {
|
|
1200
|
+
path: { endpointId, clusterId, attributeId },
|
|
1201
|
+
value,
|
|
1202
|
+
version,
|
|
1203
|
+
} = data;
|
|
1204
|
+
|
|
1205
|
+
if (value === undefined) throw new MatterFlowError("Received empty subscription result value.");
|
|
1206
|
+
const { value: oldValue, version: oldVersion } =
|
|
1207
|
+
this.#nodeStore?.retrieveAttribute(endpointId, clusterId, attributeId) ?? {};
|
|
1208
|
+
const changed = oldValue !== undefined ? !isDeepEqual(oldValue, value) : undefined;
|
|
1209
|
+
if (changed !== false || version !== oldVersion) {
|
|
1210
|
+
await this.#nodeStore?.persistAttributes([data], scope);
|
|
1211
|
+
}
|
|
1212
|
+
logger.debug(
|
|
1213
|
+
`Received attribute update${changed ? "(value changed)" : ""}: ${resolveAttributeName({
|
|
1214
|
+
endpointId,
|
|
1215
|
+
clusterId,
|
|
1216
|
+
attributeId,
|
|
1217
|
+
})} = ${serialize(value)} (version=${version})`,
|
|
1218
|
+
);
|
|
1219
|
+
|
|
1220
|
+
attributeListener?.(data, changed, oldValue);
|
|
1221
|
+
}
|
|
1222
|
+
}
|
|
1223
|
+
|
|
1148
1224
|
async invoke<C extends Command<any, any, any>>(options: {
|
|
1149
1225
|
endpointId?: EndpointNumber;
|
|
1150
1226
|
clusterId: ClusterId;
|
|
@@ -1439,31 +1515,6 @@ export class InteractionClient {
|
|
|
1439
1515
|
}
|
|
1440
1516
|
}
|
|
1441
1517
|
|
|
1442
|
-
/**
|
|
1443
|
-
* Allows to add the data received by e.g. a Read request to the cache
|
|
1444
|
-
*/
|
|
1445
|
-
async addAttributesToCache(attributeReports: DecodedAttributeReportValue<any>[]) {
|
|
1446
|
-
for (const data of attributeReports) {
|
|
1447
|
-
const {
|
|
1448
|
-
path: { endpointId, clusterId, attributeId },
|
|
1449
|
-
value,
|
|
1450
|
-
version,
|
|
1451
|
-
} = data;
|
|
1452
|
-
if (value === undefined) continue;
|
|
1453
|
-
const { value: oldValue, version: oldVersion } =
|
|
1454
|
-
this.#nodeStore?.retrieveAttribute(endpointId, clusterId, attributeId) ?? {};
|
|
1455
|
-
const changed =
|
|
1456
|
-
oldVersion !== undefined
|
|
1457
|
-
? oldVersion !== version
|
|
1458
|
-
: oldValue !== undefined
|
|
1459
|
-
? !isDeepEqual(oldValue, value)
|
|
1460
|
-
: undefined;
|
|
1461
|
-
if (changed !== false) {
|
|
1462
|
-
await this.#nodeStore?.persistAttributes([data]);
|
|
1463
|
-
}
|
|
1464
|
-
}
|
|
1465
|
-
}
|
|
1466
|
-
|
|
1467
1518
|
/**
|
|
1468
1519
|
* Returns the list (optionally filtered by endpointId and/or clusterId) of the dataVersions of the currently cached
|
|
1469
1520
|
* values to use them as knownDataVersion for read or subscription requests.
|
|
@@ -1482,4 +1533,14 @@ export class InteractionClient {
|
|
|
1482
1533
|
get maxKnownEventNumber() {
|
|
1483
1534
|
return this.#nodeStore?.maxEventNumber;
|
|
1484
1535
|
}
|
|
1536
|
+
|
|
1537
|
+
cleanupAttributeData(endpointId: EndpointNumber, clusterIds?: ClusterId[]): MaybePromise<void> {
|
|
1538
|
+
return this.#nodeStore?.cleanupAttributeData(endpointId, clusterIds);
|
|
1539
|
+
}
|
|
1540
|
+
|
|
1541
|
+
getAllCachedClusterData() {
|
|
1542
|
+
const result = new Array<DecodedAttributeReportValue<any>>();
|
|
1543
|
+
this.#enrichCachedAttributeData(result, this.getCachedClusterDataVersions());
|
|
1544
|
+
return result;
|
|
1545
|
+
}
|
|
1485
1546
|
}
|