@matter/node 0.17.7-alpha.0-20260724-baac832f7 → 0.17.7
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/system/controller/ControllerBehavior.d.ts +8 -0
- package/dist/cjs/behavior/system/controller/ControllerBehavior.d.ts.map +1 -1
- package/dist/cjs/behavior/system/controller/ControllerBehavior.js +11 -0
- package/dist/cjs/behavior/system/controller/ControllerBehavior.js.map +1 -1
- package/dist/cjs/node/ClientNode.d.ts.map +1 -1
- package/dist/cjs/node/ClientNode.js +2 -2
- package/dist/cjs/node/ClientNode.js.map +1 -1
- package/dist/cjs/node/Node.d.ts +6 -0
- package/dist/cjs/node/Node.d.ts.map +1 -1
- package/dist/cjs/node/Node.js +8 -0
- package/dist/cjs/node/Node.js.map +1 -1
- package/dist/cjs/node/NodePhysicalProperties.d.ts.map +1 -1
- package/dist/cjs/node/NodePhysicalProperties.js +23 -0
- package/dist/cjs/node/NodePhysicalProperties.js.map +1 -1
- package/dist/cjs/node/client/ClientStructure.d.ts.map +1 -1
- package/dist/cjs/node/client/ClientStructure.js +3 -2
- package/dist/cjs/node/client/ClientStructure.js.map +1 -1
- package/dist/cjs/node/client/PeerBehavior.d.ts +6 -1
- package/dist/cjs/node/client/PeerBehavior.d.ts.map +1 -1
- package/dist/cjs/node/client/PeerBehavior.js +11 -6
- package/dist/cjs/node/client/PeerBehavior.js.map +1 -1
- package/dist/esm/behavior/system/controller/ControllerBehavior.d.ts +8 -0
- package/dist/esm/behavior/system/controller/ControllerBehavior.d.ts.map +1 -1
- package/dist/esm/behavior/system/controller/ControllerBehavior.js +11 -0
- package/dist/esm/behavior/system/controller/ControllerBehavior.js.map +1 -1
- package/dist/esm/node/ClientNode.d.ts.map +1 -1
- package/dist/esm/node/ClientNode.js +3 -3
- package/dist/esm/node/ClientNode.js.map +1 -1
- package/dist/esm/node/Node.d.ts +6 -0
- package/dist/esm/node/Node.d.ts.map +1 -1
- package/dist/esm/node/Node.js +8 -0
- package/dist/esm/node/Node.js.map +1 -1
- package/dist/esm/node/NodePhysicalProperties.d.ts.map +1 -1
- package/dist/esm/node/NodePhysicalProperties.js +23 -0
- package/dist/esm/node/NodePhysicalProperties.js.map +1 -1
- package/dist/esm/node/client/ClientStructure.d.ts.map +1 -1
- package/dist/esm/node/client/ClientStructure.js +4 -4
- package/dist/esm/node/client/ClientStructure.js.map +1 -1
- package/dist/esm/node/client/PeerBehavior.d.ts +6 -1
- package/dist/esm/node/client/PeerBehavior.d.ts.map +1 -1
- package/dist/esm/node/client/PeerBehavior.js +11 -6
- package/dist/esm/node/client/PeerBehavior.js.map +1 -1
- package/package.json +6 -6
- package/src/behavior/system/controller/ControllerBehavior.ts +14 -0
- package/src/node/ClientNode.ts +4 -4
- package/src/node/Node.ts +9 -0
- package/src/node/NodePhysicalProperties.ts +49 -0
- package/src/node/client/ClientStructure.ts +3 -3
- package/src/node/client/PeerBehavior.ts +25 -7
|
@@ -12,6 +12,7 @@ import { IcdManagementClient } from "#behaviors/icd-management";
|
|
|
12
12
|
import { NetworkCommissioningClient } from "#behaviors/network-commissioning";
|
|
13
13
|
import { PowerSourceClient } from "#behaviors/power-source";
|
|
14
14
|
import { ThreadNetworkDiagnosticsClient } from "#behaviors/thread-network-diagnostics";
|
|
15
|
+
import { WiFiNetworkDiagnosticsClient } from "#behaviors/wi-fi-network-diagnostics";
|
|
15
16
|
import { Endpoint } from "#endpoint/Endpoint.js";
|
|
16
17
|
import { AggregatorEndpoint } from "#endpoints/aggregator";
|
|
17
18
|
import { Node } from "#node/Node.js";
|
|
@@ -50,9 +51,57 @@ export function NodePhysicalProperties(node: Node) {
|
|
|
50
51
|
|
|
51
52
|
inspectEndpoint(node, properties);
|
|
52
53
|
|
|
54
|
+
if (!properties.supportsWifi && !properties.supportsThread && !properties.supportsEthernet) {
|
|
55
|
+
inferNetworkMediumFromDiagnostics(node, properties);
|
|
56
|
+
}
|
|
57
|
+
|
|
53
58
|
return properties;
|
|
54
59
|
}
|
|
55
60
|
|
|
61
|
+
/**
|
|
62
|
+
* Determine the operational medium of a node that reports no network interfaces via Network Commissioning ("commissioned
|
|
63
|
+
* by other means") from the network diagnostics cluster of the medium it operates on.
|
|
64
|
+
*
|
|
65
|
+
* The mandatory diagnostics attributes are all nullable and null while the interface is not associated, so a populated
|
|
66
|
+
* one distinguishes an operational interface from a cluster that merely exists.
|
|
67
|
+
*
|
|
68
|
+
* Diagnostics describe the node itself, so only the root endpoint is considered.
|
|
69
|
+
*/
|
|
70
|
+
function inferNetworkMediumFromDiagnostics(node: Node, properties: PhysicalDeviceProperties) {
|
|
71
|
+
const wifiDiagnosticsType = node.behaviors.typeFor(WiFiNetworkDiagnosticsClient);
|
|
72
|
+
const wifi = wifiDiagnosticsType ? node.maybeStateOf(wifiDiagnosticsType) : undefined;
|
|
73
|
+
if (wifi?.bssid !== undefined && wifi.bssid !== null) {
|
|
74
|
+
properties.supportsWifi = true;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const threadDiagnosticsType = node.behaviors.typeFor(ThreadNetworkDiagnosticsClient);
|
|
78
|
+
const thread = threadDiagnosticsType ? node.maybeStateOf(threadDiagnosticsType) : undefined;
|
|
79
|
+
if (
|
|
80
|
+
thread !== undefined &&
|
|
81
|
+
(isPresent(thread.extendedPanId) ||
|
|
82
|
+
isPresent(thread.panId) ||
|
|
83
|
+
isPresent(thread.channel) ||
|
|
84
|
+
isPresent(thread.networkName))
|
|
85
|
+
) {
|
|
86
|
+
properties.supportsThread = true;
|
|
87
|
+
|
|
88
|
+
// A null extended PAN ID leaves threadActive false. When Thread is the only medium the node reports we trust
|
|
89
|
+
// the remaining details instead, otherwise the node stays unclassified despite being reachable.
|
|
90
|
+
if (
|
|
91
|
+
!properties.supportsWifi &&
|
|
92
|
+
properties.wifiActive === undefined &&
|
|
93
|
+
properties.ethernetActive === undefined
|
|
94
|
+
) {
|
|
95
|
+
properties.threadActive = true;
|
|
96
|
+
properties.threadChannel ??= thread.channel ?? undefined;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function isPresent(value: unknown) {
|
|
102
|
+
return value !== undefined && value !== null;
|
|
103
|
+
}
|
|
104
|
+
|
|
56
105
|
// Device types are collected node-wide (including bridged endpoints behind an aggregator) so consumers such as the
|
|
57
106
|
// subscription-interval policy can react to them. Power/network/thread properties describe the physical node itself,
|
|
58
107
|
// so bridged endpoints (behindAggregator) must not contribute to them.
|
|
@@ -32,7 +32,6 @@ import {
|
|
|
32
32
|
DeviceClassification,
|
|
33
33
|
FeatureMap,
|
|
34
34
|
GeneratedCommandList,
|
|
35
|
-
Matter,
|
|
36
35
|
type FeatureBitmap,
|
|
37
36
|
} from "@matter/model";
|
|
38
37
|
import { ReadScope, Val, type Read, type ReadResult } from "@matter/protocol";
|
|
@@ -689,6 +688,7 @@ export class ClientStructure {
|
|
|
689
688
|
if (this.#commandFactory) {
|
|
690
689
|
shape.commandFactory = this.#commandFactory;
|
|
691
690
|
}
|
|
691
|
+
shape.matter = this.#node.matter;
|
|
692
692
|
const behaviorType = PeerBehavior(shape);
|
|
693
693
|
|
|
694
694
|
if (endpoint.lifecycle.isInstalled) {
|
|
@@ -730,7 +730,7 @@ export class ClientStructure {
|
|
|
730
730
|
}
|
|
731
731
|
|
|
732
732
|
let isApp = false;
|
|
733
|
-
const model =
|
|
733
|
+
const model = this.#node.matter.deviceTypes(dt.deviceType);
|
|
734
734
|
if (model !== undefined) {
|
|
735
735
|
isApp = DeviceClassification.isApplication(model.classification);
|
|
736
736
|
}
|
|
@@ -917,7 +917,7 @@ export class ClientStructure {
|
|
|
917
917
|
}
|
|
918
918
|
|
|
919
919
|
// Try to resolve by looking up the cluster model by capitalized behavior name (e.g. "onOff" → "OnOff")
|
|
920
|
-
const clusterModel =
|
|
920
|
+
const clusterModel = this.#node.matter.clusters(capitalize(behaviorId));
|
|
921
921
|
if (clusterModel) {
|
|
922
922
|
return this.#clusterFor(endpoint, clusterModel.id as ClusterId);
|
|
923
923
|
}
|
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
FeatureBitmap,
|
|
19
19
|
FeatureSet,
|
|
20
20
|
Matter,
|
|
21
|
+
MatterModel,
|
|
21
22
|
type ValueModel,
|
|
22
23
|
} from "@matter/model";
|
|
23
24
|
import { AttributeId, ClusterId, CommandId } from "@matter/types";
|
|
@@ -25,7 +26,10 @@ import { ClientCommandMethod } from "./ClientCommandMethod.js";
|
|
|
25
26
|
|
|
26
27
|
const BIT_BLOCK_SIZE = Math.log2(Number.MAX_SAFE_INTEGER);
|
|
27
28
|
|
|
28
|
-
const discoveredCaches = new Map<
|
|
29
|
+
const discoveredCaches = new Map<
|
|
30
|
+
ClusterBehaviorType.CommandFactory,
|
|
31
|
+
WeakMap<MatterModel, Record<string, ClusterBehavior.Type>>
|
|
32
|
+
>();
|
|
29
33
|
const knownCaches = new Map<ClusterBehaviorType.CommandFactory, WeakMap<ClusterBehavior.Type, ClusterBehavior.Type>>();
|
|
30
34
|
|
|
31
35
|
const isPeer = Symbol("is-peer");
|
|
@@ -73,6 +77,12 @@ export namespace PeerBehavior {
|
|
|
73
77
|
commands?: CommandId[];
|
|
74
78
|
generatedCommands?: CommandId[];
|
|
75
79
|
commandFactory?: ClusterBehaviorType.CommandFactory;
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Model used to resolve standard element names/shapes. Defaults to the global {@link Matter} model; a client
|
|
83
|
+
* node supplies its own so custom or extended clusters resolve to real names.
|
|
84
|
+
*/
|
|
85
|
+
matter?: MatterModel;
|
|
76
86
|
}
|
|
77
87
|
|
|
78
88
|
/**
|
|
@@ -86,12 +96,17 @@ export namespace PeerBehavior {
|
|
|
86
96
|
}
|
|
87
97
|
|
|
88
98
|
function instrumentDiscoveredShape(shape: PeerBehavior.DiscoveredClusterShape) {
|
|
89
|
-
const
|
|
99
|
+
const matter = shape.matter ?? Matter;
|
|
100
|
+
const analysis = DiscoveredShapeAnalysis(shape, matter);
|
|
90
101
|
const factory = shape.commandFactory ?? ClientCommandMethod;
|
|
91
102
|
|
|
92
|
-
let
|
|
103
|
+
let byModel = discoveredCaches.get(factory);
|
|
104
|
+
if (!byModel) {
|
|
105
|
+
discoveredCaches.set(factory, (byModel = new WeakMap()));
|
|
106
|
+
}
|
|
107
|
+
let cache = byModel.get(matter);
|
|
93
108
|
if (!cache) {
|
|
94
|
-
|
|
109
|
+
byModel.set(matter, (cache = {}));
|
|
95
110
|
}
|
|
96
111
|
|
|
97
112
|
const fingerprint = createFingerprint(analysis);
|
|
@@ -102,7 +117,7 @@ function instrumentDiscoveredShape(shape: PeerBehavior.DiscoveredClusterShape) {
|
|
|
102
117
|
|
|
103
118
|
// Find a base behavior for the standard cluster, if available
|
|
104
119
|
let baseType: Behavior.Type | undefined;
|
|
105
|
-
const standardSchema =
|
|
120
|
+
const standardSchema = matter.get(ClusterModel, shape.id);
|
|
106
121
|
if (standardSchema) {
|
|
107
122
|
// Create a base behavior from the standard schema
|
|
108
123
|
baseType = ClusterBehaviorType({
|
|
@@ -360,8 +375,11 @@ interface DiscoveredShapeAnalysis {
|
|
|
360
375
|
/**
|
|
361
376
|
* Analyze a discovered cluster shape to determine how we should override the behavior and schema.
|
|
362
377
|
*/
|
|
363
|
-
function DiscoveredShapeAnalysis(
|
|
364
|
-
|
|
378
|
+
function DiscoveredShapeAnalysis(
|
|
379
|
+
shape: PeerBehavior.DiscoveredClusterShape,
|
|
380
|
+
matter: MatterModel = Matter,
|
|
381
|
+
): DiscoveredShapeAnalysis {
|
|
382
|
+
const standardCluster = matter.clusters(shape.id);
|
|
365
383
|
const schema =
|
|
366
384
|
standardCluster ??
|
|
367
385
|
new ClusterModel({ id: shape.id, name: createUnknownName("Cluster", shape.id), revision: shape.revision });
|