@matter/node 0.16.0-alpha.0-20251115-d89e62680 → 0.16.0-alpha.0-20251129-96ad07c6e
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/behavior/Events.js +1 -1
- package/dist/cjs/behavior/cluster/ClientBehavior.d.ts +1 -1
- package/dist/cjs/behavior/cluster/ClusterBehavior.d.ts +1 -1
- package/dist/cjs/behavior/cluster/ClusterBehaviorType.d.ts +1 -1
- package/dist/cjs/behavior/cluster/ClusterBehaviorType.js +3 -3
- package/dist/cjs/behavior/cluster/ClusterBehaviorType.js.map +1 -1
- package/dist/cjs/behavior/state/validation/ValueValidator.js +14 -4
- package/dist/cjs/behavior/state/validation/ValueValidator.js.map +1 -1
- package/dist/cjs/behavior/state/validation/assertions.d.ts.map +1 -1
- package/dist/cjs/behavior/state/validation/assertions.js +21 -0
- package/dist/cjs/behavior/state/validation/assertions.js.map +1 -1
- package/dist/cjs/behavior/system/commissioning/CommissioningClient.d.ts.map +1 -1
- package/dist/cjs/behavior/system/commissioning/CommissioningClient.js +1 -3
- package/dist/cjs/behavior/system/commissioning/CommissioningClient.js.map +1 -1
- package/dist/cjs/behavior/system/controller/ControllerBehavior.d.ts +2 -0
- package/dist/cjs/behavior/system/controller/ControllerBehavior.d.ts.map +1 -1
- package/dist/cjs/behavior/system/controller/ControllerBehavior.js +5 -2
- package/dist/cjs/behavior/system/controller/ControllerBehavior.js.map +1 -1
- package/dist/cjs/behavior/system/network/ServerNetworkRuntime.d.ts +1 -0
- package/dist/cjs/behavior/system/network/ServerNetworkRuntime.d.ts.map +1 -1
- package/dist/cjs/behavior/system/network/ServerNetworkRuntime.js +8 -2
- package/dist/cjs/behavior/system/network/ServerNetworkRuntime.js.map +1 -1
- package/dist/cjs/behaviors/general-diagnostics/GeneralDiagnosticsServer.d.ts.map +1 -1
- package/dist/cjs/behaviors/general-diagnostics/GeneralDiagnosticsServer.js +88 -34
- package/dist/cjs/behaviors/general-diagnostics/GeneralDiagnosticsServer.js.map +1 -1
- package/dist/cjs/behaviors/group-key-management/GroupKeyManagementServer.d.ts.map +1 -1
- package/dist/cjs/behaviors/group-key-management/GroupKeyManagementServer.js +15 -2
- package/dist/cjs/behaviors/group-key-management/GroupKeyManagementServer.js.map +1 -1
- package/dist/cjs/behaviors/identify/IdentifyServer.d.ts.map +1 -1
- package/dist/cjs/behaviors/identify/IdentifyServer.js +5 -0
- package/dist/cjs/behaviors/identify/IdentifyServer.js.map +1 -1
- package/dist/cjs/behaviors/service-area/ServiceAreaServer.js +1 -1
- package/dist/cjs/behaviors/switch/SwitchServer.js +2 -2
- package/dist/cjs/behaviors/thermostat/ThermostatServer.d.ts +10 -0
- package/dist/cjs/behaviors/thermostat/ThermostatServer.d.ts.map +1 -1
- package/dist/cjs/behaviors/thermostat/ThermostatServer.js +59 -22
- package/dist/cjs/behaviors/thermostat/ThermostatServer.js.map +1 -1
- package/dist/cjs/endpoint/Endpoint.d.ts +2 -2
- package/dist/cjs/endpoint/Endpoint.d.ts.map +1 -1
- package/dist/cjs/endpoint/properties/Endpoints.d.ts +2 -2
- package/dist/cjs/endpoint/properties/Endpoints.d.ts.map +1 -1
- package/dist/cjs/endpoint/properties/Endpoints.js +12 -1
- package/dist/cjs/endpoint/properties/Endpoints.js.map +1 -1
- package/dist/cjs/node/ClientNode.d.ts +7 -2
- package/dist/cjs/node/ClientNode.d.ts.map +1 -1
- package/dist/cjs/node/ClientNode.js +10 -3
- package/dist/cjs/node/ClientNode.js.map +1 -1
- package/dist/cjs/node/Node.d.ts.map +1 -1
- package/dist/cjs/node/Node.js +9 -3
- package/dist/cjs/node/Node.js.map +1 -1
- package/dist/cjs/node/NodeLifecycle.d.ts +1 -1
- package/dist/cjs/node/NodeLifecycle.js +1 -1
- package/dist/cjs/node/ServerNode.d.ts.map +1 -1
- package/dist/cjs/node/ServerNode.js +11 -4
- package/dist/cjs/node/ServerNode.js.map +1 -1
- package/dist/cjs/node/client/ClientEndpointInitializer.js +1 -1
- package/dist/cjs/node/client/ClientEndpointInitializer.js.map +1 -1
- package/dist/cjs/node/client/ClientEventEmitter.d.ts.map +1 -1
- package/dist/cjs/node/client/ClientEventEmitter.js +8 -3
- package/dist/cjs/node/client/ClientEventEmitter.js.map +1 -1
- package/dist/cjs/node/client/ClientStructure.d.ts.map +1 -1
- package/dist/cjs/node/client/ClientStructure.js +80 -96
- package/dist/cjs/node/client/ClientStructure.js.map +1 -1
- package/dist/cjs/node/client/Peers.d.ts.map +1 -1
- package/dist/cjs/node/client/Peers.js +22 -4
- package/dist/cjs/node/client/Peers.js.map +1 -1
- package/dist/cjs/node/server/ServerEnvironment.d.ts.map +1 -1
- package/dist/cjs/node/server/ServerEnvironment.js +0 -3
- package/dist/cjs/node/server/ServerEnvironment.js.map +1 -1
- package/dist/esm/behavior/Events.js +1 -1
- package/dist/esm/behavior/cluster/ClientBehavior.d.ts +1 -1
- package/dist/esm/behavior/cluster/ClusterBehavior.d.ts +1 -1
- package/dist/esm/behavior/cluster/ClusterBehaviorType.d.ts +1 -1
- package/dist/esm/behavior/cluster/ClusterBehaviorType.js +3 -3
- package/dist/esm/behavior/cluster/ClusterBehaviorType.js.map +1 -1
- package/dist/esm/behavior/state/validation/ValueValidator.js +14 -4
- package/dist/esm/behavior/state/validation/ValueValidator.js.map +1 -1
- package/dist/esm/behavior/state/validation/assertions.d.ts.map +1 -1
- package/dist/esm/behavior/state/validation/assertions.js +22 -1
- package/dist/esm/behavior/state/validation/assertions.js.map +1 -1
- package/dist/esm/behavior/system/commissioning/CommissioningClient.d.ts.map +1 -1
- package/dist/esm/behavior/system/commissioning/CommissioningClient.js +1 -3
- package/dist/esm/behavior/system/commissioning/CommissioningClient.js.map +1 -1
- package/dist/esm/behavior/system/controller/ControllerBehavior.d.ts +2 -0
- package/dist/esm/behavior/system/controller/ControllerBehavior.d.ts.map +1 -1
- package/dist/esm/behavior/system/controller/ControllerBehavior.js +5 -2
- package/dist/esm/behavior/system/controller/ControllerBehavior.js.map +1 -1
- package/dist/esm/behavior/system/network/ServerNetworkRuntime.d.ts +1 -0
- package/dist/esm/behavior/system/network/ServerNetworkRuntime.d.ts.map +1 -1
- package/dist/esm/behavior/system/network/ServerNetworkRuntime.js +8 -2
- package/dist/esm/behavior/system/network/ServerNetworkRuntime.js.map +1 -1
- package/dist/esm/behaviors/general-diagnostics/GeneralDiagnosticsServer.d.ts.map +1 -1
- package/dist/esm/behaviors/general-diagnostics/GeneralDiagnosticsServer.js +88 -34
- package/dist/esm/behaviors/general-diagnostics/GeneralDiagnosticsServer.js.map +1 -1
- package/dist/esm/behaviors/group-key-management/GroupKeyManagementServer.d.ts.map +1 -1
- package/dist/esm/behaviors/group-key-management/GroupKeyManagementServer.js +16 -3
- package/dist/esm/behaviors/group-key-management/GroupKeyManagementServer.js.map +1 -1
- package/dist/esm/behaviors/identify/IdentifyServer.d.ts.map +1 -1
- package/dist/esm/behaviors/identify/IdentifyServer.js +5 -0
- package/dist/esm/behaviors/identify/IdentifyServer.js.map +1 -1
- package/dist/esm/behaviors/service-area/ServiceAreaServer.js +1 -1
- package/dist/esm/behaviors/switch/SwitchServer.js +2 -2
- package/dist/esm/behaviors/thermostat/ThermostatServer.d.ts +10 -0
- package/dist/esm/behaviors/thermostat/ThermostatServer.d.ts.map +1 -1
- package/dist/esm/behaviors/thermostat/ThermostatServer.js +59 -22
- package/dist/esm/behaviors/thermostat/ThermostatServer.js.map +1 -1
- package/dist/esm/endpoint/Endpoint.d.ts +2 -2
- package/dist/esm/endpoint/Endpoint.d.ts.map +1 -1
- package/dist/esm/endpoint/properties/Endpoints.d.ts +2 -2
- package/dist/esm/endpoint/properties/Endpoints.d.ts.map +1 -1
- package/dist/esm/endpoint/properties/Endpoints.js +12 -1
- package/dist/esm/endpoint/properties/Endpoints.js.map +1 -1
- package/dist/esm/node/ClientNode.d.ts +7 -2
- package/dist/esm/node/ClientNode.d.ts.map +1 -1
- package/dist/esm/node/ClientNode.js +10 -3
- package/dist/esm/node/ClientNode.js.map +1 -1
- package/dist/esm/node/Node.d.ts.map +1 -1
- package/dist/esm/node/Node.js +9 -3
- package/dist/esm/node/Node.js.map +1 -1
- package/dist/esm/node/NodeLifecycle.d.ts +1 -1
- package/dist/esm/node/NodeLifecycle.js +1 -1
- package/dist/esm/node/ServerNode.d.ts.map +1 -1
- package/dist/esm/node/ServerNode.js +11 -4
- package/dist/esm/node/ServerNode.js.map +1 -1
- package/dist/esm/node/client/ClientEndpointInitializer.js +1 -1
- package/dist/esm/node/client/ClientEndpointInitializer.js.map +1 -1
- package/dist/esm/node/client/ClientEventEmitter.d.ts.map +1 -1
- package/dist/esm/node/client/ClientEventEmitter.js +9 -4
- package/dist/esm/node/client/ClientEventEmitter.js.map +1 -1
- package/dist/esm/node/client/ClientStructure.d.ts.map +1 -1
- package/dist/esm/node/client/ClientStructure.js +80 -96
- package/dist/esm/node/client/ClientStructure.js.map +1 -1
- package/dist/esm/node/client/Peers.d.ts.map +1 -1
- package/dist/esm/node/client/Peers.js +24 -5
- package/dist/esm/node/client/Peers.js.map +1 -1
- package/dist/esm/node/server/ServerEnvironment.d.ts.map +1 -1
- package/dist/esm/node/server/ServerEnvironment.js +1 -4
- package/dist/esm/node/server/ServerEnvironment.js.map +1 -1
- package/package.json +7 -7
- package/src/behavior/Events.ts +1 -1
- package/src/behavior/cluster/ClientBehavior.ts +1 -1
- package/src/behavior/cluster/ClusterBehavior.ts +1 -1
- package/src/behavior/cluster/ClusterBehaviorType.ts +4 -5
- package/src/behavior/cluster/ValidatedElements.ts +1 -1
- package/src/behavior/state/validation/ValueValidator.ts +16 -4
- package/src/behavior/state/validation/assertions.ts +27 -1
- package/src/behavior/system/commissioning/CommissioningClient.ts +2 -4
- package/src/behavior/system/controller/ControllerBehavior.ts +8 -3
- package/src/behavior/system/network/ServerNetworkRuntime.ts +11 -2
- package/src/behaviors/general-diagnostics/GeneralDiagnosticsServer.ts +2 -1
- package/src/behaviors/group-key-management/GroupKeyManagementServer.ts +19 -3
- package/src/behaviors/identify/IdentifyServer.ts +9 -0
- package/src/behaviors/service-area/ServiceAreaServer.ts +1 -1
- package/src/behaviors/switch/SwitchServer.ts +2 -2
- package/src/behaviors/thermostat/ThermostatServer.ts +65 -22
- package/src/endpoint/Endpoint.ts +2 -2
- package/src/endpoint/properties/Endpoints.ts +16 -3
- package/src/node/ClientNode.ts +11 -4
- package/src/node/Node.ts +10 -3
- package/src/node/NodeLifecycle.ts +1 -1
- package/src/node/ServerNode.ts +12 -4
- package/src/node/client/ClientEndpointInitializer.ts +1 -1
- package/src/node/client/ClientEventEmitter.ts +9 -4
- package/src/node/client/ClientStructure.ts +67 -22
- package/src/node/client/Peers.ts +31 -4
- package/src/node/server/ServerEnvironment.ts +1 -6
|
@@ -22,6 +22,8 @@ import {
|
|
|
22
22
|
Observable,
|
|
23
23
|
} from "#general";
|
|
24
24
|
import { FieldElement } from "#model";
|
|
25
|
+
import { Node } from "#node/index.js";
|
|
26
|
+
import { ServerNode } from "#node/ServerNode.js";
|
|
25
27
|
import { hasLocalActor, Val } from "#protocol";
|
|
26
28
|
import { ClusterType, StatusResponse, TypeFromPartialBitSchema } from "#types";
|
|
27
29
|
import { AtomicWriteHandler } from "./AtomicWriteHandler.js";
|
|
@@ -123,10 +125,11 @@ export class ThermostatBaseServer extends ThermostatBehaviorLogicBase {
|
|
|
123
125
|
throw new ImplementationError("minSetpointDeadBand is out of valid range 0..127");
|
|
124
126
|
}
|
|
125
127
|
|
|
128
|
+
const node = Node.forEndpoint(this.endpoint);
|
|
129
|
+
this.reactTo(node.lifecycle.online, this.#nodeOnline);
|
|
130
|
+
|
|
126
131
|
// Initialize all the validation and logic handling
|
|
127
132
|
this.#setupValidations();
|
|
128
|
-
this.#setupTemperatureMeasurementIntegration();
|
|
129
|
-
this.#setupOccupancyIntegration();
|
|
130
133
|
this.#setupModeHandling();
|
|
131
134
|
this.#setupThermostatLogic();
|
|
132
135
|
this.#setupPresets();
|
|
@@ -136,6 +139,13 @@ export class ThermostatBaseServer extends ThermostatBehaviorLogicBase {
|
|
|
136
139
|
this.internal.controlSequenceOfOperation = this.state.controlSequenceOfOperation;
|
|
137
140
|
}
|
|
138
141
|
|
|
142
|
+
#nodeOnline() {
|
|
143
|
+
// TODO Also react to structure changes to add/remove endpoints that are being added or removed but might be used
|
|
144
|
+
// for temperature or occupancy sensing
|
|
145
|
+
this.#setupTemperatureMeasurementIntegration();
|
|
146
|
+
this.#setupOccupancyIntegration();
|
|
147
|
+
}
|
|
148
|
+
|
|
139
149
|
/**
|
|
140
150
|
* The default implementation of the SetpointRaiseLower command. It handles all validation and setpoint adjustments
|
|
141
151
|
* required by the Matter specification. This method only changes the Occupied setpoints.
|
|
@@ -415,20 +425,29 @@ export class ThermostatBaseServer extends ThermostatBehaviorLogicBase {
|
|
|
415
425
|
}
|
|
416
426
|
|
|
417
427
|
let localTemperature = null;
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
);
|
|
422
|
-
if (
|
|
428
|
+
const localTempEndpoint = this.state.localIndoorTemperatureMeasurementEndpoint;
|
|
429
|
+
if (!preferRemoteTemperature && localTempEndpoint !== undefined) {
|
|
430
|
+
const endpoints = this.env.get(ServerNode).endpoints;
|
|
431
|
+
const endpoint = endpoints.has(localTempEndpoint) ? endpoints.for(localTempEndpoint) : undefined;
|
|
432
|
+
if (endpoint !== undefined && endpoint.behaviors.has(TemperatureMeasurementServer)) {
|
|
433
|
+
logger.debug(
|
|
434
|
+
`Using existing TemperatureMeasurement cluster on endpoint #${localTempEndpoint} for local temperature measurement`,
|
|
435
|
+
);
|
|
436
|
+
if (this.state.externalMeasuredIndoorTemperature !== undefined) {
|
|
437
|
+
logger.warn(
|
|
438
|
+
"Both local TemperatureMeasurement cluster and externalMeasuredIndoorTemperature state are set, using local cluster",
|
|
439
|
+
);
|
|
440
|
+
}
|
|
441
|
+
this.reactTo(
|
|
442
|
+
endpoint.eventsOf(TemperatureMeasurementServer).measuredValue$Changed,
|
|
443
|
+
this.#handleMeasuredTemperatureChange,
|
|
444
|
+
);
|
|
445
|
+
localTemperature = endpoint.stateOf(TemperatureMeasurementServer).measuredValue;
|
|
446
|
+
} else {
|
|
423
447
|
logger.warn(
|
|
424
|
-
|
|
448
|
+
`No TemperatureMeasurement cluster found on endpoint #${localTempEndpoint}, falling back to externalMeasuredIndoorTemperature state if set`,
|
|
425
449
|
);
|
|
426
450
|
}
|
|
427
|
-
this.reactTo(
|
|
428
|
-
this.agent.get(TemperatureMeasurementServer).events.measuredValue$Changed,
|
|
429
|
-
this.#handleMeasuredTemperatureChange,
|
|
430
|
-
);
|
|
431
|
-
localTemperature = this.endpoint.stateOf(TemperatureMeasurementServer).measuredValue;
|
|
432
451
|
} else {
|
|
433
452
|
if (this.state.externalMeasuredIndoorTemperature === undefined) {
|
|
434
453
|
logger.warn(
|
|
@@ -440,7 +459,9 @@ export class ThermostatBaseServer extends ThermostatBehaviorLogicBase {
|
|
|
440
459
|
}
|
|
441
460
|
this.reactTo(this.events.externalMeasuredIndoorTemperature$Changed, this.#handleMeasuredTemperatureChange);
|
|
442
461
|
}
|
|
443
|
-
|
|
462
|
+
if (localTemperature !== null) {
|
|
463
|
+
this.#handleMeasuredTemperatureChange(localTemperature); // and initialize
|
|
464
|
+
}
|
|
444
465
|
}
|
|
445
466
|
|
|
446
467
|
/**
|
|
@@ -472,20 +493,30 @@ export class ThermostatBaseServer extends ThermostatBehaviorLogicBase {
|
|
|
472
493
|
if (!this.features.occupancy) {
|
|
473
494
|
return;
|
|
474
495
|
}
|
|
475
|
-
let currentOccupancy
|
|
496
|
+
let currentOccupancy = true;
|
|
476
497
|
const preferRemoteOccupancy = !!this.state.remoteSensing?.occupancy;
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
498
|
+
const localOccupancyEndpoint = this.state.localOccupancyMeasurementEndpoint;
|
|
499
|
+
if (!preferRemoteOccupancy && localOccupancyEndpoint !== undefined) {
|
|
500
|
+
const endpoints = this.env.get(ServerNode).endpoints;
|
|
501
|
+
const endpoint = endpoints.has(localOccupancyEndpoint) ? endpoints.for(localOccupancyEndpoint) : undefined;
|
|
502
|
+
if (endpoint !== undefined && endpoint.behaviors.has(OccupancySensingServer)) {
|
|
503
|
+
logger.debug(
|
|
504
|
+
`Using existing OccupancySensing cluster on endpoint ${localOccupancyEndpoint} for local occupancy sensing`,
|
|
505
|
+
);
|
|
506
|
+
if (this.state.externallyMeasuredOccupancy !== undefined) {
|
|
507
|
+
logger.warn(
|
|
508
|
+
"Both local OccupancySensing cluster and externallyMeasuredOccupancy state are set, using local cluster",
|
|
509
|
+
);
|
|
510
|
+
}
|
|
511
|
+
this.reactTo(endpoint.eventsOf(OccupancySensingServer).occupancy$Changed, this.#handleOccupancyChange);
|
|
512
|
+
currentOccupancy = !!endpoint.stateOf(OccupancySensingServer).occupancy.occupied;
|
|
513
|
+
} else {
|
|
480
514
|
logger.warn(
|
|
481
|
-
|
|
515
|
+
`No OccupancySensing cluster found on endpoint ${localOccupancyEndpoint}, falling back to externallyMeasuredOccupancy state if set`,
|
|
482
516
|
);
|
|
483
517
|
}
|
|
484
|
-
this.reactTo(this.agent.get(OccupancySensingServer).events.occupancy$Changed, this.#handleOccupancyChange);
|
|
485
|
-
currentOccupancy = !!this.endpoint.stateOf(OccupancySensingServer).occupancy.occupied;
|
|
486
518
|
} else {
|
|
487
519
|
if (this.state.externallyMeasuredOccupancy === undefined) {
|
|
488
|
-
currentOccupancy = true;
|
|
489
520
|
logger.warn(
|
|
490
521
|
"No local OccupancySensing cluster available and externallyMeasuredOccupancy state not set",
|
|
491
522
|
);
|
|
@@ -1354,6 +1385,12 @@ export namespace ThermostatBaseServer {
|
|
|
1354
1385
|
*/
|
|
1355
1386
|
externalMeasuredIndoorTemperature?: number;
|
|
1356
1387
|
|
|
1388
|
+
/**
|
|
1389
|
+
* Endpoint (Number or string-Id) where to find the indoor temperature measurement cluster to use as
|
|
1390
|
+
* local temperature measurement for the thermostat behavior.
|
|
1391
|
+
*/
|
|
1392
|
+
localIndoorTemperatureMeasurementEndpoint?: number | string;
|
|
1393
|
+
|
|
1357
1394
|
/**
|
|
1358
1395
|
* Otherwise measured occupancy as boolean.
|
|
1359
1396
|
* Use this if you have an external occupancy sensor that should be used for thermostat control instead of a
|
|
@@ -1361,6 +1398,12 @@ export namespace ThermostatBaseServer {
|
|
|
1361
1398
|
*/
|
|
1362
1399
|
externallyMeasuredOccupancy?: boolean;
|
|
1363
1400
|
|
|
1401
|
+
/**
|
|
1402
|
+
* Endpoint (Number or string-Id) where to find the occupancy sensing cluster to use as
|
|
1403
|
+
* local occupancy measurement for the thermostat behavior.
|
|
1404
|
+
*/
|
|
1405
|
+
localOccupancyMeasurementEndpoint?: number | string;
|
|
1406
|
+
|
|
1364
1407
|
/**
|
|
1365
1408
|
* Use to enable the automatic mode management, implemented by this standard implementation. This is beyond
|
|
1366
1409
|
* Matter specification! It reacts to temperature changes to adjust system running mode automatically. It also
|
package/src/endpoint/Endpoint.ts
CHANGED
|
@@ -203,12 +203,12 @@ export class Endpoint<T extends EndpointType = EndpointType.Empty> {
|
|
|
203
203
|
/**
|
|
204
204
|
* Version of {@link stateOf} that returns undefined instead of throwing if the requested behavior unsupported.
|
|
205
205
|
*/
|
|
206
|
-
maybeStateOf(type: string): Immutable<Val.Struct
|
|
206
|
+
maybeStateOf(type: string): Immutable<Val.Struct> | undefined;
|
|
207
207
|
|
|
208
208
|
/**
|
|
209
209
|
* Version of {@link stateOf} that returns undefined instead of throwing if the requested behavior unsupported.
|
|
210
210
|
*/
|
|
211
|
-
maybeStateOf<T extends Behavior.Type>(type: T): Immutable<Behavior.StateOf<T
|
|
211
|
+
maybeStateOf<T extends Behavior.Type>(type: T): Immutable<Behavior.StateOf<T>> | undefined;
|
|
212
212
|
|
|
213
213
|
maybeStateOf(type: Behavior.Type | string) {
|
|
214
214
|
if (typeof type === "string") {
|
|
@@ -25,7 +25,7 @@ export class Endpoints implements ImmutableSet<Endpoint> {
|
|
|
25
25
|
return this.#node;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
has(endpoint: Endpoint | number): boolean {
|
|
28
|
+
has(endpoint: Endpoint | number | string): boolean {
|
|
29
29
|
if (endpoint === this.#node || endpoint === 0) {
|
|
30
30
|
return true;
|
|
31
31
|
}
|
|
@@ -34,6 +34,10 @@ export class Endpoints implements ImmutableSet<Endpoint> {
|
|
|
34
34
|
return endpoint in this.#index;
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
+
if (typeof endpoint === "string") {
|
|
38
|
+
return endpoint in this.#idIndex;
|
|
39
|
+
}
|
|
40
|
+
|
|
37
41
|
return endpoint.lifecycle.hasNumber && endpoint.number in this.#index;
|
|
38
42
|
}
|
|
39
43
|
|
|
@@ -57,12 +61,12 @@ export class Endpoints implements ImmutableSet<Endpoint> {
|
|
|
57
61
|
return this.#list[Symbol.iterator]();
|
|
58
62
|
}
|
|
59
63
|
|
|
60
|
-
for(number: number): Endpoint {
|
|
64
|
+
for(number: number | string): Endpoint {
|
|
61
65
|
if (number === 0) {
|
|
62
66
|
return this.#node;
|
|
63
67
|
}
|
|
64
68
|
|
|
65
|
-
const endpoint = this.#index[number];
|
|
69
|
+
const endpoint = typeof number === "string" ? this.#idIndex[number] : this.#index[number];
|
|
66
70
|
if (endpoint === undefined) {
|
|
67
71
|
throw new StatusResponse.NotFoundError(`Endpoint ${number} does not exist`);
|
|
68
72
|
}
|
|
@@ -78,6 +82,15 @@ export class Endpoints implements ImmutableSet<Endpoint> {
|
|
|
78
82
|
return this.#node.behaviors.internalsOf(IndexBehavior).partsByNumber;
|
|
79
83
|
}
|
|
80
84
|
|
|
85
|
+
/**
|
|
86
|
+
* Object mapping Endpoint-Id -> Endpoint.
|
|
87
|
+
*
|
|
88
|
+
* Note that this does not include endpoint 0, but we have that in #node.
|
|
89
|
+
*/
|
|
90
|
+
get #idIndex() {
|
|
91
|
+
return this.#node.behaviors.internalsOf(IndexBehavior).partsById;
|
|
92
|
+
}
|
|
93
|
+
|
|
81
94
|
/**
|
|
82
95
|
* Full list of endpoints. Includes endpoint 0.
|
|
83
96
|
*/
|
package/src/node/ClientNode.ts
CHANGED
|
@@ -110,22 +110,29 @@ export class ClientNode extends Node<ClientNode.RootEndpoint> {
|
|
|
110
110
|
|
|
111
111
|
/**
|
|
112
112
|
* Remove this node from the fabric (if commissioned) and locally.
|
|
113
|
+
* This method tries to communicate with the device to decommission it properly and will fail if the device is
|
|
114
|
+
* unreachable.
|
|
115
|
+
* If you can not reach the device, use {@link delete} instead.
|
|
113
116
|
*/
|
|
114
|
-
|
|
117
|
+
async decommission() {
|
|
115
118
|
if (this.lifecycle.isCommissioned) {
|
|
116
119
|
this.statusUpdate("decommissioning");
|
|
117
120
|
|
|
118
121
|
await this.act("decommission", agent => agent.commissioning.decommission());
|
|
119
122
|
}
|
|
120
|
-
|
|
121
|
-
await super.delete();
|
|
123
|
+
await this.delete();
|
|
122
124
|
}
|
|
123
125
|
|
|
124
126
|
/**
|
|
125
127
|
* Force-remove the node without first decommissioning.
|
|
126
128
|
*
|
|
127
|
-
* If the node is still available you should use {@link
|
|
129
|
+
* If the node is still available you should use {@link decommission} to remove it properly from the fabric and only use
|
|
130
|
+
* this method as fallback. You should also tell the user that he needs to manually factory-reset the device.
|
|
128
131
|
*/
|
|
132
|
+
override async delete() {
|
|
133
|
+
await super.delete();
|
|
134
|
+
}
|
|
135
|
+
|
|
129
136
|
override async erase() {
|
|
130
137
|
await this.lifecycle.mutex.produce(this.eraseWithMutex.bind(this));
|
|
131
138
|
}
|
package/src/node/Node.ts
CHANGED
|
@@ -40,6 +40,7 @@ const logger = Logger.get("Node");
|
|
|
40
40
|
export abstract class Node<T extends Node.CommonRootEndpoint = Node.CommonRootEndpoint> extends Endpoint<T> {
|
|
41
41
|
#environment: Environment;
|
|
42
42
|
#runtime?: NetworkRuntime;
|
|
43
|
+
#startInProgress = false;
|
|
43
44
|
|
|
44
45
|
constructor(config: Node.Configuration<T>) {
|
|
45
46
|
const parentEnvironment = config.environment ?? config.owner?.env ?? Environment.default;
|
|
@@ -96,12 +97,18 @@ export abstract class Node<T extends Node.CommonRootEndpoint = Node.CommonRootEn
|
|
|
96
97
|
* Bring the node online.
|
|
97
98
|
*/
|
|
98
99
|
async start() {
|
|
99
|
-
if (this.lifecycle.isOnline) {
|
|
100
|
+
if (this.lifecycle.isOnline || this.#startInProgress) {
|
|
100
101
|
return;
|
|
101
102
|
}
|
|
102
|
-
this.lifecycle.targetState = "online";
|
|
103
103
|
|
|
104
|
-
|
|
104
|
+
this.#startInProgress = true;
|
|
105
|
+
try {
|
|
106
|
+
this.lifecycle.targetState = "online";
|
|
107
|
+
|
|
108
|
+
await this.lifecycle.mutex.produce(this.startWithMutex.bind(this));
|
|
109
|
+
} finally {
|
|
110
|
+
this.#startInProgress = false;
|
|
111
|
+
}
|
|
105
112
|
}
|
|
106
113
|
|
|
107
114
|
protected async startWithMutex() {
|
package/src/node/ServerNode.ts
CHANGED
|
@@ -105,13 +105,16 @@ export class ServerNode<T extends ServerNode.RootEndpoint = ServerNode.RootEndpo
|
|
|
105
105
|
}
|
|
106
106
|
|
|
107
107
|
override async [Construction.destruct]() {
|
|
108
|
+
if (this.#peers) {
|
|
109
|
+
await this.#peers.close();
|
|
110
|
+
}
|
|
111
|
+
|
|
108
112
|
await super[Construction.destruct]();
|
|
109
113
|
await ServerEnvironment.close(this);
|
|
110
114
|
}
|
|
111
115
|
|
|
112
116
|
override async prepareRuntimeShutdown() {
|
|
113
|
-
|
|
114
|
-
await sessions.close();
|
|
117
|
+
await this.env.get(SessionManager).closeAllSessions();
|
|
115
118
|
}
|
|
116
119
|
|
|
117
120
|
/**
|
|
@@ -160,8 +163,13 @@ export class ServerNode<T extends ServerNode.RootEndpoint = ServerNode.RootEndpo
|
|
|
160
163
|
*/
|
|
161
164
|
get peers() {
|
|
162
165
|
if (!this.#peers) {
|
|
163
|
-
|
|
164
|
-
|
|
166
|
+
try {
|
|
167
|
+
this.#peers = new Peers(this);
|
|
168
|
+
this.#peers.initialize();
|
|
169
|
+
} catch (e) {
|
|
170
|
+
this.#peers = undefined;
|
|
171
|
+
throw e;
|
|
172
|
+
}
|
|
165
173
|
}
|
|
166
174
|
|
|
167
175
|
return this.#peers;
|
|
@@ -59,7 +59,7 @@ export class ClientEndpointInitializer extends EndpointInitializer {
|
|
|
59
59
|
|
|
60
60
|
// Activate remote behavior
|
|
61
61
|
const store = this.structure.storeForRemote(endpoint, peerType);
|
|
62
|
-
return new ClientBehaviorBacking(endpoint,
|
|
62
|
+
return new ClientBehaviorBacking(endpoint, peerType, store, endpoint.behaviors.optionsFor(peerType));
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
get structure() {
|
|
@@ -5,11 +5,11 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import type { ElementEvent, Events } from "#behavior/Events.js";
|
|
8
|
-
import { camelize, Diagnostic, Logger } from "#general";
|
|
8
|
+
import { camelize, Diagnostic, isObject, Logger } from "#general";
|
|
9
9
|
import { ClusterModel, EventModel, MatterModel } from "#model";
|
|
10
10
|
import type { ClientNode } from "#node/ClientNode.js";
|
|
11
11
|
import type { ReadResult } from "#protocol";
|
|
12
|
-
import type { ClusterId,
|
|
12
|
+
import type { ClusterId, EventId } from "#types";
|
|
13
13
|
import type { ClientStructure } from "./ClientStructure.js";
|
|
14
14
|
|
|
15
15
|
const logger = Logger.get("ClientEventEmitter");
|
|
@@ -46,7 +46,7 @@ export function ClientEventEmitter(node: ClientNode, structure: ClientStructure)
|
|
|
46
46
|
return;
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
const event = getEvent(node, occurrence
|
|
49
|
+
const event = getEvent(node, occurrence, names.cluster, names.event);
|
|
50
50
|
if (event) {
|
|
51
51
|
node.act(agent => {
|
|
52
52
|
// Current ActionContext is not writable, could skip act() but meh, see TODO above
|
|
@@ -56,7 +56,11 @@ export function ClientEventEmitter(node: ClientNode, structure: ClientStructure)
|
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
function getEvent(node: ClientNode,
|
|
59
|
+
function getEvent(node: ClientNode, occurrence: ReadResult.EventValue, clusterName: string, eventName: string) {
|
|
60
|
+
const {
|
|
61
|
+
value,
|
|
62
|
+
path: { endpointId },
|
|
63
|
+
} = occurrence;
|
|
60
64
|
const endpoint = structure.endpointFor(endpointId);
|
|
61
65
|
if (endpoint === undefined) {
|
|
62
66
|
logger.warn(`Received event for unsupported endpoint #${endpointId} on ${node}`);
|
|
@@ -74,6 +78,7 @@ export function ClientEventEmitter(node: ClientNode, structure: ClientStructure)
|
|
|
74
78
|
Diagnostic.strong(`${clusterName}.${eventName}`),
|
|
75
79
|
" on ",
|
|
76
80
|
Diagnostic.strong(endpoint.toString()),
|
|
81
|
+
Diagnostic.weak(isObject(value) ? Diagnostic.dict(value) : value),
|
|
77
82
|
);
|
|
78
83
|
|
|
79
84
|
return events[eventName];
|
|
@@ -28,6 +28,7 @@ import { ReadScope, type Read, type ReadResult } from "#protocol";
|
|
|
28
28
|
import { DatasourceCache } from "#storage/client/DatasourceCache.js";
|
|
29
29
|
import { ClientNodeStore } from "#storage/index.js";
|
|
30
30
|
import type { AttributeId, ClusterId, ClusterType, CommandId, EndpointNumber } from "#types";
|
|
31
|
+
import { Status } from "#types";
|
|
31
32
|
import { ClientEventEmitter } from "./ClientEventEmitter.js";
|
|
32
33
|
import { ClientStructureEvents } from "./ClientStructureEvents.js";
|
|
33
34
|
import { PeerBehavior } from "./PeerBehavior.js";
|
|
@@ -44,11 +45,12 @@ const PARTS_LIST_ATTR_ID = Descriptor.Cluster.attributes.partsList.id;
|
|
|
44
45
|
export class ClientStructure {
|
|
45
46
|
#nodeStore: ClientNodeStore;
|
|
46
47
|
#endpoints = new Map<EndpointNumber, EndpointStructure>();
|
|
47
|
-
#
|
|
48
|
+
#eventEmitter: ClientEventEmitter;
|
|
48
49
|
#node: ClientNode;
|
|
49
50
|
#subscribedFabricFiltered?: boolean;
|
|
50
51
|
#pendingChanges = new Map<EndpointStructure, PendingChange>();
|
|
51
|
-
#
|
|
52
|
+
#pendingStructureEvents = Array<PendingEvent>();
|
|
53
|
+
#delayedClusterEvents = new Array<ReadResult.EventValue>();
|
|
52
54
|
#events: ClientStructureEvents;
|
|
53
55
|
|
|
54
56
|
constructor(node: ClientNode) {
|
|
@@ -58,7 +60,7 @@ export class ClientStructure {
|
|
|
58
60
|
endpoint: node,
|
|
59
61
|
clusters: new Map(),
|
|
60
62
|
});
|
|
61
|
-
this.#
|
|
63
|
+
this.#eventEmitter = ClientEventEmitter(node, this);
|
|
62
64
|
this.#events = this.#node.env.get(ClientStructureEvents);
|
|
63
65
|
}
|
|
64
66
|
|
|
@@ -103,7 +105,7 @@ export class ClientStructure {
|
|
|
103
105
|
this.#install(structure);
|
|
104
106
|
}
|
|
105
107
|
|
|
106
|
-
this.#
|
|
108
|
+
this.#emitPendingStructureEvents();
|
|
107
109
|
}
|
|
108
110
|
|
|
109
111
|
/**
|
|
@@ -167,9 +169,6 @@ export class ClientStructure {
|
|
|
167
169
|
* Update the node structure by applying attribute changes.
|
|
168
170
|
*/
|
|
169
171
|
async *mutate(request: Read, changes: ReadResult) {
|
|
170
|
-
// Ensure mutations run serially and integrate properly with node lifecycle
|
|
171
|
-
using _lock = await this.#node.lifecycle.mutex.lock();
|
|
172
|
-
|
|
173
172
|
// We collect updates and only apply when we transition clusters
|
|
174
173
|
let currentUpdates: AttributeUpdates | undefined;
|
|
175
174
|
|
|
@@ -183,10 +182,18 @@ export class ClientStructure {
|
|
|
183
182
|
break;
|
|
184
183
|
|
|
185
184
|
case "event-value":
|
|
186
|
-
this.#emitEvent(change);
|
|
185
|
+
this.#emitEvent(change, currentUpdates);
|
|
187
186
|
break;
|
|
188
187
|
|
|
189
|
-
|
|
188
|
+
case "attr-status":
|
|
189
|
+
case "event-status":
|
|
190
|
+
logger.debug(
|
|
191
|
+
"Received status for",
|
|
192
|
+
change.kind === "attr-status" ? "attribute" : "event",
|
|
193
|
+
Diagnostic.strong(change.path.toString()),
|
|
194
|
+
`: ${Status[change.status]}#${change.status}${change.clusterStatus !== undefined ? `/${Status[change.clusterStatus]}#${change.clusterStatus}` : ""}`,
|
|
195
|
+
);
|
|
196
|
+
break;
|
|
190
197
|
}
|
|
191
198
|
}
|
|
192
199
|
|
|
@@ -218,7 +225,7 @@ export class ClientStructure {
|
|
|
218
225
|
}
|
|
219
226
|
|
|
220
227
|
// Likewise, we don't emit events until we've applied all structural changes
|
|
221
|
-
this.#
|
|
228
|
+
this.#emitPendingStructureEvents();
|
|
222
229
|
}
|
|
223
230
|
|
|
224
231
|
/** Reference to the default subscription used when the node was started. */
|
|
@@ -273,6 +280,21 @@ export class ClientStructure {
|
|
|
273
280
|
return currentUpdates;
|
|
274
281
|
}
|
|
275
282
|
|
|
283
|
+
#emitEvent(occurrence: ReadResult.EventValue, currentUpdates?: AttributeUpdates) {
|
|
284
|
+
const { endpointId, clusterId } = occurrence.path;
|
|
285
|
+
|
|
286
|
+
const endpoint = this.#endpoints.get(endpointId);
|
|
287
|
+
// If we are building updates on current cluster or endpoint has pending changes, delay event emission
|
|
288
|
+
if (
|
|
289
|
+
(currentUpdates && (currentUpdates.endpointId === endpointId || currentUpdates.clusterId === clusterId)) ||
|
|
290
|
+
(endpoint !== undefined && this.#pendingChanges?.has(endpoint))
|
|
291
|
+
) {
|
|
292
|
+
this.#delayedClusterEvents.push(occurrence);
|
|
293
|
+
} else {
|
|
294
|
+
this.#eventEmitter(occurrence);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
276
298
|
/**
|
|
277
299
|
* Obtain the {@link ClusterType} for an {@link EndpointNumber} and {@link ClusterId}.
|
|
278
300
|
*/
|
|
@@ -308,13 +330,27 @@ export class ClientStructure {
|
|
|
308
330
|
}
|
|
309
331
|
|
|
310
332
|
if (cluster.behavior && AttributeList.id in attrs.values) {
|
|
311
|
-
|
|
333
|
+
const attributeList = attrs.values[AttributeList.id];
|
|
334
|
+
if (
|
|
335
|
+
Array.isArray(attributeList) &&
|
|
336
|
+
!isDeepEqual(
|
|
337
|
+
cluster.attributes,
|
|
338
|
+
attributeList.sort((a, b) => a - b),
|
|
339
|
+
)
|
|
340
|
+
) {
|
|
312
341
|
cluster.behavior = undefined;
|
|
313
342
|
}
|
|
314
343
|
}
|
|
315
344
|
|
|
316
345
|
if (cluster.behavior && AcceptedCommandList.id in attrs.values) {
|
|
317
|
-
|
|
346
|
+
const acceptedCommands = attrs.values[AcceptedCommandList.id];
|
|
347
|
+
if (
|
|
348
|
+
Array.isArray(acceptedCommands) &&
|
|
349
|
+
!isDeepEqual(
|
|
350
|
+
cluster.commands,
|
|
351
|
+
acceptedCommands.sort((a, b) => a - b),
|
|
352
|
+
)
|
|
353
|
+
) {
|
|
318
354
|
cluster.behavior = undefined;
|
|
319
355
|
}
|
|
320
356
|
}
|
|
@@ -353,11 +389,15 @@ export class ClientStructure {
|
|
|
353
389
|
}
|
|
354
390
|
|
|
355
391
|
if (Array.isArray(attributeList)) {
|
|
356
|
-
cluster.attributes = attributeList.filter(attr => typeof attr === "number") as AttributeId[]
|
|
392
|
+
cluster.attributes = (attributeList.filter(attr => typeof attr === "number") as AttributeId[]).sort(
|
|
393
|
+
(a, b) => a - b,
|
|
394
|
+
);
|
|
357
395
|
}
|
|
358
396
|
|
|
359
397
|
if (Array.isArray(commandList)) {
|
|
360
|
-
cluster.commands = commandList.filter(cmd => typeof cmd === "number") as CommandId[]
|
|
398
|
+
cluster.commands = (commandList.filter(cmd => typeof cmd === "number") as CommandId[]).sort(
|
|
399
|
+
(a, b) => a - b,
|
|
400
|
+
);
|
|
361
401
|
}
|
|
362
402
|
}
|
|
363
403
|
|
|
@@ -611,7 +651,7 @@ export class ClientStructure {
|
|
|
611
651
|
logger.error("Error clearing cluster storage:", e);
|
|
612
652
|
}
|
|
613
653
|
|
|
614
|
-
this.#
|
|
654
|
+
this.#pendingStructureEvents.push({
|
|
615
655
|
kind: "cluster",
|
|
616
656
|
endpoint: structure,
|
|
617
657
|
cluster,
|
|
@@ -632,7 +672,7 @@ export class ClientStructure {
|
|
|
632
672
|
cluster.behavior = pendingBehavior;
|
|
633
673
|
delete cluster.pendingBehavior;
|
|
634
674
|
|
|
635
|
-
this.#
|
|
675
|
+
this.#pendingStructureEvents.push({
|
|
636
676
|
kind: "cluster",
|
|
637
677
|
subkind,
|
|
638
678
|
endpoint: structure,
|
|
@@ -651,7 +691,7 @@ export class ClientStructure {
|
|
|
651
691
|
if (pendingOwner) {
|
|
652
692
|
endpoint.owner = pendingOwner.endpoint;
|
|
653
693
|
structure.pendingOwner = undefined;
|
|
654
|
-
this.#
|
|
694
|
+
this.#pendingStructureEvents.push({ kind: "endpoint", endpoint: structure });
|
|
655
695
|
}
|
|
656
696
|
|
|
657
697
|
// Handle behavior installation
|
|
@@ -672,7 +712,7 @@ export class ClientStructure {
|
|
|
672
712
|
// We emit cluster events during the endpoint event so only add cluster event manually if the endpoint is
|
|
673
713
|
// already installed
|
|
674
714
|
if (!pendingOwner) {
|
|
675
|
-
this.#
|
|
715
|
+
this.#pendingStructureEvents.push({
|
|
676
716
|
kind: "cluster",
|
|
677
717
|
subkind: "add",
|
|
678
718
|
endpoint: structure,
|
|
@@ -700,10 +740,12 @@ export class ClientStructure {
|
|
|
700
740
|
* We do this after all structural updates are complete so that listeners can expect composed parts and dependent
|
|
701
741
|
* behaviors to be installed.
|
|
702
742
|
*/
|
|
703
|
-
#
|
|
704
|
-
const
|
|
705
|
-
|
|
706
|
-
|
|
743
|
+
#emitPendingStructureEvents() {
|
|
744
|
+
const structureEvents = this.#pendingStructureEvents;
|
|
745
|
+
const clusterEvents = this.#delayedClusterEvents;
|
|
746
|
+
this.#delayedClusterEvents = [];
|
|
747
|
+
this.#pendingStructureEvents = [];
|
|
748
|
+
for (const event of structureEvents) {
|
|
707
749
|
switch (event.kind) {
|
|
708
750
|
case "endpoint": {
|
|
709
751
|
const {
|
|
@@ -747,6 +789,9 @@ export class ClientStructure {
|
|
|
747
789
|
}
|
|
748
790
|
}
|
|
749
791
|
}
|
|
792
|
+
for (const occurrence of clusterEvents) {
|
|
793
|
+
this.#eventEmitter(occurrence);
|
|
794
|
+
}
|
|
750
795
|
}
|
|
751
796
|
}
|
|
752
797
|
|
package/src/node/client/Peers.ts
CHANGED
|
@@ -29,6 +29,7 @@ import {
|
|
|
29
29
|
Seconds,
|
|
30
30
|
Time,
|
|
31
31
|
Timestamp,
|
|
32
|
+
UninitializedDependencyError,
|
|
32
33
|
} from "#general";
|
|
33
34
|
import { ClientGroup } from "#node/ClientGroup.js";
|
|
34
35
|
import { InteractionServer } from "#node/server/InteractionServer.js";
|
|
@@ -69,6 +70,10 @@ export class Peers extends EndpointContainer<ClientNode> {
|
|
|
69
70
|
this.deleted.on(this.#manageExpiration.bind(this));
|
|
70
71
|
|
|
71
72
|
this.clusterInstalled(BasicInformationClient).on(this.#instrumentBasicInformation.bind(this));
|
|
73
|
+
|
|
74
|
+
const lifecycle = owner.lifecycle;
|
|
75
|
+
lifecycle.online.on(this.#nodeOnline.bind(this));
|
|
76
|
+
lifecycle.offline.on(this.#nodeOffline.bind(this));
|
|
72
77
|
}
|
|
73
78
|
|
|
74
79
|
/**
|
|
@@ -77,7 +82,14 @@ export class Peers extends EndpointContainer<ClientNode> {
|
|
|
77
82
|
initialize() {
|
|
78
83
|
const factory = this.owner.env.get(ClientNodeFactory);
|
|
79
84
|
|
|
80
|
-
const clientStores = this.owner.env.
|
|
85
|
+
const clientStores = this.owner.env.maybeGet(ServerNodeStore)?.clientStores;
|
|
86
|
+
if (clientStores === undefined) {
|
|
87
|
+
throw new UninitializedDependencyError(
|
|
88
|
+
"Peers",
|
|
89
|
+
"are not available because ServerNode initialization is incomplete",
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
|
|
81
93
|
// Group nodes have an in-memory only store, so all nodes restored here are ClientNode
|
|
82
94
|
for (const id of clientStores.knownIds) {
|
|
83
95
|
this.add(
|
|
@@ -89,6 +101,21 @@ export class Peers extends EndpointContainer<ClientNode> {
|
|
|
89
101
|
}
|
|
90
102
|
}
|
|
91
103
|
|
|
104
|
+
async #nodeOnline() {
|
|
105
|
+
// TODO start all peers on node startup in a non blocking way respecting queuing for thread and such
|
|
106
|
+
/*for (const peer of this) {
|
|
107
|
+
await peer.start();
|
|
108
|
+
}*/
|
|
109
|
+
this.#manageExpiration();
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
async #nodeOffline() {
|
|
113
|
+
this.#cancelExpiration();
|
|
114
|
+
for (const peer of this) {
|
|
115
|
+
await peer.cancel();
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
92
119
|
/**
|
|
93
120
|
* Find a specific commissionable node.
|
|
94
121
|
*/
|
|
@@ -330,13 +357,13 @@ export class Peers extends EndpointContainer<ClientNode> {
|
|
|
330
357
|
|
|
331
358
|
#onLeave(node: ClientNode, fabricIndex: FabricIndex) {
|
|
332
359
|
this.#mutex.run(async () => {
|
|
333
|
-
const { fabrics: peerFabrics } = node.maybeStateOf(OperationalCredentialsClient);
|
|
334
|
-
const peerFabric = peerFabrics
|
|
360
|
+
const { fabrics: peerFabrics } = node.maybeStateOf(OperationalCredentialsClient) ?? {};
|
|
361
|
+
const peerFabric = peerFabrics?.find(fabric => fabric.fabricIndex === fabricIndex);
|
|
335
362
|
if (!peerFabric) {
|
|
336
363
|
return;
|
|
337
364
|
}
|
|
338
365
|
|
|
339
|
-
const peerAddress = node.maybeStateOf(CommissioningClient)
|
|
366
|
+
const peerAddress = node.maybeStateOf(CommissioningClient)?.peerAddress;
|
|
340
367
|
if (!peerAddress) {
|
|
341
368
|
return;
|
|
342
369
|
}
|