@matter-server/dashboard 0.2.0-alpha.0-00000000-000000000
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/LICENSE +201 -0
- package/README.md +11 -0
- package/dist/esm/client/client-context.d.ts +10 -0
- package/dist/esm/client/client-context.d.ts.map +1 -0
- package/dist/esm/client/client-context.js +11 -0
- package/dist/esm/client/client-context.js.map +6 -0
- package/dist/esm/client/models/descriptions.d.ts +20 -0
- package/dist/esm/client/models/descriptions.d.ts.map +1 -0
- package/dist/esm/client/models/descriptions.js +10929 -0
- package/dist/esm/client/models/descriptions.js.map +6 -0
- package/dist/esm/components/dialog-box/dialog-box.d.ts +25 -0
- package/dist/esm/components/dialog-box/dialog-box.d.ts.map +1 -0
- package/dist/esm/components/dialog-box/dialog-box.js +66 -0
- package/dist/esm/components/dialog-box/dialog-box.js.map +6 -0
- package/dist/esm/components/dialog-box/show-dialog-box.d.ts +18 -0
- package/dist/esm/components/dialog-box/show-dialog-box.d.ts.map +1 -0
- package/dist/esm/components/dialog-box/show-dialog-box.js +22 -0
- package/dist/esm/components/dialog-box/show-dialog-box.js.map +6 -0
- package/dist/esm/components/dialogs/acl/model.d.ts +33 -0
- package/dist/esm/components/dialogs/acl/model.d.ts.map +1 -0
- package/dist/esm/components/dialogs/acl/model.js +79 -0
- package/dist/esm/components/dialogs/acl/model.js.map +6 -0
- package/dist/esm/components/dialogs/binding/model.d.ts +20 -0
- package/dist/esm/components/dialogs/binding/model.d.ts.map +1 -0
- package/dist/esm/components/dialogs/binding/model.js +45 -0
- package/dist/esm/components/dialogs/binding/model.js.map +6 -0
- package/dist/esm/components/dialogs/binding/node-binding-dialog.d.ts +49 -0
- package/dist/esm/components/dialogs/binding/node-binding-dialog.d.ts.map +1 -0
- package/dist/esm/components/dialogs/binding/node-binding-dialog.js +357 -0
- package/dist/esm/components/dialogs/binding/node-binding-dialog.js.map +6 -0
- package/dist/esm/components/dialogs/binding/show-node-binding-dialog.d.ts +8 -0
- package/dist/esm/components/dialogs/binding/show-node-binding-dialog.d.ts.map +1 -0
- package/dist/esm/components/dialogs/binding/show-node-binding-dialog.js +17 -0
- package/dist/esm/components/dialogs/binding/show-node-binding-dialog.js.map +6 -0
- package/dist/esm/components/dialogs/commission-node-dialog/commission-node-dialog.d.ts +31 -0
- package/dist/esm/components/dialogs/commission-node-dialog/commission-node-dialog.d.ts.map +1 -0
- package/dist/esm/components/dialogs/commission-node-dialog/commission-node-dialog.js +94 -0
- package/dist/esm/components/dialogs/commission-node-dialog/commission-node-dialog.js.map +6 -0
- package/dist/esm/components/dialogs/commission-node-dialog/commission-node-existing.d.ts +17 -0
- package/dist/esm/components/dialogs/commission-node-dialog/commission-node-existing.d.ts.map +1 -0
- package/dist/esm/components/dialogs/commission-node-dialog/commission-node-existing.js +64 -0
- package/dist/esm/components/dialogs/commission-node-dialog/commission-node-existing.js.map +6 -0
- package/dist/esm/components/dialogs/commission-node-dialog/commission-node-thread.d.ts +19 -0
- package/dist/esm/components/dialogs/commission-node-dialog/commission-node-thread.d.ts.map +1 -0
- package/dist/esm/components/dialogs/commission-node-dialog/commission-node-thread.js +91 -0
- package/dist/esm/components/dialogs/commission-node-dialog/commission-node-thread.js.map +6 -0
- package/dist/esm/components/dialogs/commission-node-dialog/commission-node-wifi.d.ts +20 -0
- package/dist/esm/components/dialogs/commission-node-dialog/commission-node-wifi.d.ts.map +1 -0
- package/dist/esm/components/dialogs/commission-node-dialog/commission-node-wifi.js +106 -0
- package/dist/esm/components/dialogs/commission-node-dialog/commission-node-wifi.js.map +6 -0
- package/dist/esm/components/dialogs/commission-node-dialog/show-commission-node-dialog.d.ts +8 -0
- package/dist/esm/components/dialogs/commission-node-dialog/show-commission-node-dialog.d.ts.map +1 -0
- package/dist/esm/components/dialogs/commission-node-dialog/show-commission-node-dialog.js +15 -0
- package/dist/esm/components/dialogs/commission-node-dialog/show-commission-node-dialog.js.map +6 -0
- package/dist/esm/components/ha-svg-icon.d.ts +19 -0
- package/dist/esm/components/ha-svg-icon.d.ts.map +1 -0
- package/dist/esm/components/ha-svg-icon.js +77 -0
- package/dist/esm/components/ha-svg-icon.js.map +6 -0
- package/dist/esm/entrypoint/main.d.ts +7 -0
- package/dist/esm/entrypoint/main.d.ts.map +1 -0
- package/dist/esm/entrypoint/main.js +45 -0
- package/dist/esm/entrypoint/main.js.map +6 -0
- package/dist/esm/package.json +3 -0
- package/dist/esm/pages/components/context.d.ts +9 -0
- package/dist/esm/pages/components/context.d.ts.map +1 -0
- package/dist/esm/pages/components/context.js +11 -0
- package/dist/esm/pages/components/context.js.map +6 -0
- package/dist/esm/pages/components/footer.d.ts +11 -0
- package/dist/esm/pages/components/footer.d.ts.map +1 -0
- package/dist/esm/pages/components/footer.js +52 -0
- package/dist/esm/pages/components/footer.js.map +6 -0
- package/dist/esm/pages/components/header.d.ts +27 -0
- package/dist/esm/pages/components/header.d.ts.map +1 -0
- package/dist/esm/pages/components/header.js +90 -0
- package/dist/esm/pages/components/header.js.map +6 -0
- package/dist/esm/pages/components/node-details.d.ts +29 -0
- package/dist/esm/pages/components/node-details.d.ts.map +1 -0
- package/dist/esm/pages/components/node-details.js +241 -0
- package/dist/esm/pages/components/node-details.js.map +6 -0
- package/dist/esm/pages/components/server-details.d.ts +24 -0
- package/dist/esm/pages/components/server-details.d.ts.map +1 -0
- package/dist/esm/pages/components/server-details.js +130 -0
- package/dist/esm/pages/components/server-details.js.map +6 -0
- package/dist/esm/pages/matter-cluster-view.d.ts +30 -0
- package/dist/esm/pages/matter-cluster-view.d.ts.map +1 -0
- package/dist/esm/pages/matter-cluster-view.js +154 -0
- package/dist/esm/pages/matter-cluster-view.js.map +6 -0
- package/dist/esm/pages/matter-dashboard-app.d.ts +27 -0
- package/dist/esm/pages/matter-dashboard-app.d.ts.map +1 -0
- package/dist/esm/pages/matter-dashboard-app.js +122 -0
- package/dist/esm/pages/matter-dashboard-app.js.map +6 -0
- package/dist/esm/pages/matter-endpoint-view.d.ts +29 -0
- package/dist/esm/pages/matter-endpoint-view.d.ts.map +1 -0
- package/dist/esm/pages/matter-endpoint-view.js +149 -0
- package/dist/esm/pages/matter-endpoint-view.js.map +6 -0
- package/dist/esm/pages/matter-node-view.d.ts +28 -0
- package/dist/esm/pages/matter-node-view.d.ts.map +1 -0
- package/dist/esm/pages/matter-node-view.js +122 -0
- package/dist/esm/pages/matter-node-view.js.map +6 -0
- package/dist/esm/pages/matter-server-view.d.ts +31 -0
- package/dist/esm/pages/matter-server-view.d.ts.map +1 -0
- package/dist/esm/pages/matter-server-view.js +113 -0
- package/dist/esm/pages/matter-server-view.js.map +6 -0
- package/dist/esm/util/clone_class.d.ts +7 -0
- package/dist/esm/util/clone_class.d.ts.map +1 -0
- package/dist/esm/util/clone_class.js +10 -0
- package/dist/esm/util/clone_class.js.map +6 -0
- package/dist/esm/util/fire_event.d.ts +34 -0
- package/dist/esm/util/fire_event.d.ts.map +1 -0
- package/dist/esm/util/fire_event.js +21 -0
- package/dist/esm/util/fire_event.js.map +6 -0
- package/dist/esm/util/prevent_default.d.ts +7 -0
- package/dist/esm/util/prevent_default.d.ts.map +1 -0
- package/dist/esm/util/prevent_default.js +10 -0
- package/dist/esm/util/prevent_default.js.map +6 -0
- package/dist/esm/util/routing.d.ts +10 -0
- package/dist/esm/util/routing.d.ts.map +1 -0
- package/dist/esm/util/routing.js +6 -0
- package/dist/esm/util/routing.js.map +6 -0
- package/dist/web/index.html +40 -0
- package/dist/web/js/commission-node-dialog-BJsfA4IV.js +78 -0
- package/dist/web/js/commission-node-dialog-DEZ3EqYO.js +78 -0
- package/dist/web/js/commission-node-existing-CzRtUgBm.js +50 -0
- package/dist/web/js/commission-node-existing-OK1ybPFI.js +50 -0
- package/dist/web/js/commission-node-thread-DLmclivF.js +75 -0
- package/dist/web/js/commission-node-thread-FcLFz84I.js +75 -0
- package/dist/web/js/commission-node-wifi-C8ho-UYb.js +88 -0
- package/dist/web/js/commission-node-wifi-C8iGfy7c.js +88 -0
- package/dist/web/js/dialog-box-BPz-oO3d.js +52 -0
- package/dist/web/js/dialog-box-DN32sjfR.js +52 -0
- package/dist/web/js/fire_event-BERTqZpV.js +169 -0
- package/dist/web/js/fire_event-BlsbXpOL.js +169 -0
- package/dist/web/js/main.js +547 -0
- package/dist/web/js/matter-dashboard-app-5UjO1Ik8.js +16068 -0
- package/dist/web/js/matter-dashboard-app-BazvuIIi.js +16068 -0
- package/dist/web/js/node-binding-dialog-2yitVn0R.js +443 -0
- package/dist/web/js/node-binding-dialog-Cw6QEmL3.js +443 -0
- package/dist/web/js/outlined-text-field-BMLYwwlc.js +2086 -0
- package/dist/web/js/outlined-text-field-Sqd4JHxo.js +2086 -0
- package/dist/web/js/prevent_default-BsT53c0u.js +814 -0
- package/dist/web/js/prevent_default-D4GG_QeD.js +814 -0
- package/package.json +54 -0
- package/src/client/client-context.ts +10 -0
- package/src/client/models/descriptions.ts +10948 -0
- package/src/components/dialog-box/dialog-box.ts +62 -0
- package/src/components/dialog-box/show-dialog-box.ts +32 -0
- package/src/components/dialogs/acl/model.ts +105 -0
- package/src/components/dialogs/binding/model.ts +58 -0
- package/src/components/dialogs/binding/node-binding-dialog.ts +419 -0
- package/src/components/dialogs/binding/show-node-binding-dialog.ts +16 -0
- package/src/components/dialogs/commission-node-dialog/commission-node-dialog.ts +102 -0
- package/src/components/dialogs/commission-node-dialog/commission-node-existing.ts +49 -0
- package/src/components/dialogs/commission-node-dialog/commission-node-thread.ts +76 -0
- package/src/components/dialogs/commission-node-dialog/commission-node-wifi.ts +90 -0
- package/src/components/dialogs/commission-node-dialog/show-commission-node-dialog.ts +14 -0
- package/src/components/ha-svg-icon.ts +66 -0
- package/src/entrypoint/main.ts +60 -0
- package/src/pages/components/context.ts +10 -0
- package/src/pages/components/footer.ts +39 -0
- package/src/pages/components/header.ts +87 -0
- package/src/pages/components/node-details.ts +252 -0
- package/src/pages/components/server-details.ts +124 -0
- package/src/pages/matter-cluster-view.ts +162 -0
- package/src/pages/matter-dashboard-app.ts +125 -0
- package/src/pages/matter-endpoint-view.ts +152 -0
- package/src/pages/matter-node-view.ts +126 -0
- package/src/pages/matter-server-view.ts +117 -0
- package/src/tsconfig.json +16 -0
- package/src/util/clone_class.ts +7 -0
- package/src/util/fire_event.ts +83 -0
- package/src/util/prevent_default.ts +7 -0
- package/src/util/routing.ts +10 -0
|
@@ -0,0 +1,547 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025-2026 Open Home Foundation
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
const BIGINT_MARKER = "__BIGINT__";
|
|
7
|
+
function toBigIntAwareJson(value, spaces) {
|
|
8
|
+
const replacements = new Array();
|
|
9
|
+
let result = JSON.stringify(value, (_key, val) => {
|
|
10
|
+
if (typeof val === "bigint") {
|
|
11
|
+
if (val > Number.MAX_SAFE_INTEGER) {
|
|
12
|
+
replacements.push({
|
|
13
|
+
from: `"0x${val.toString(16)}"`,
|
|
14
|
+
to: val.toString()
|
|
15
|
+
});
|
|
16
|
+
return `0x${val.toString(16)}`;
|
|
17
|
+
} else {
|
|
18
|
+
return Number(val);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return val;
|
|
22
|
+
}, spaces);
|
|
23
|
+
if (replacements.length > 0) {
|
|
24
|
+
replacements.forEach(({
|
|
25
|
+
from,
|
|
26
|
+
to
|
|
27
|
+
}) => {
|
|
28
|
+
result = result.replaceAll(from, to);
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
return result;
|
|
32
|
+
}
|
|
33
|
+
function parseBigIntAwareJson(json) {
|
|
34
|
+
const processed = json.replace(/([:,[])\s*(\d{15,})(?=[,}\]\s])/g, (match, prefix, number) => {
|
|
35
|
+
const num = BigInt(number);
|
|
36
|
+
if (num > Number.MAX_SAFE_INTEGER) {
|
|
37
|
+
return `${prefix}"${BIGINT_MARKER}${number}"`;
|
|
38
|
+
}
|
|
39
|
+
return match;
|
|
40
|
+
});
|
|
41
|
+
return JSON.parse(processed, (_key, value) => {
|
|
42
|
+
if (typeof value === "string" && value.startsWith(BIGINT_MARKER)) {
|
|
43
|
+
return BigInt(value.slice(BIGINT_MARKER.length));
|
|
44
|
+
}
|
|
45
|
+
return value;
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* @license
|
|
51
|
+
* Copyright 2025-2026 Open Home Foundation
|
|
52
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
53
|
+
*/
|
|
54
|
+
class Connection {
|
|
55
|
+
/**
|
|
56
|
+
* Create a new connection.
|
|
57
|
+
* @param ws_server_url WebSocket server URL
|
|
58
|
+
* @param wsFactory Optional factory function to create WebSocket instances.
|
|
59
|
+
* If not provided, uses the global WebSocket constructor.
|
|
60
|
+
*/
|
|
61
|
+
constructor(ws_server_url, wsFactory) {
|
|
62
|
+
this.ws_server_url = ws_server_url;
|
|
63
|
+
this.ws_server_url = ws_server_url;
|
|
64
|
+
this.wsFactory = wsFactory ?? (url => new WebSocket(url));
|
|
65
|
+
}
|
|
66
|
+
serverInfo = void 0;
|
|
67
|
+
socket;
|
|
68
|
+
wsFactory;
|
|
69
|
+
get connected() {
|
|
70
|
+
var _this$socket;
|
|
71
|
+
return ((_this$socket = this.socket) === null || _this$socket === void 0 ? void 0 : _this$socket.readyState) === 1;
|
|
72
|
+
}
|
|
73
|
+
async connect(onMessage, onConnectionLost) {
|
|
74
|
+
if (this.socket) {
|
|
75
|
+
throw new Error("Already connected");
|
|
76
|
+
}
|
|
77
|
+
console.debug("Trying to connect");
|
|
78
|
+
return new Promise((resolve, reject) => {
|
|
79
|
+
this.socket = this.wsFactory(this.ws_server_url);
|
|
80
|
+
this.socket.onopen = () => {
|
|
81
|
+
console.log("WebSocket Connected");
|
|
82
|
+
};
|
|
83
|
+
this.socket.onclose = () => {
|
|
84
|
+
console.log("WebSocket Closed");
|
|
85
|
+
onConnectionLost();
|
|
86
|
+
};
|
|
87
|
+
this.socket.onerror = error => {
|
|
88
|
+
console.error("WebSocket Error: ", error);
|
|
89
|
+
reject(new Error("WebSocket Error"));
|
|
90
|
+
};
|
|
91
|
+
this.socket.onmessage = event => {
|
|
92
|
+
const dataStr = typeof event.data === "string" ? event.data : String(event.data);
|
|
93
|
+
const data = parseBigIntAwareJson(dataStr);
|
|
94
|
+
console.log("WebSocket OnMessage", data);
|
|
95
|
+
if (!this.serverInfo) {
|
|
96
|
+
this.serverInfo = data;
|
|
97
|
+
resolve();
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
onMessage(data);
|
|
101
|
+
};
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
disconnect() {
|
|
105
|
+
if (this.socket) {
|
|
106
|
+
this.socket.close();
|
|
107
|
+
this.socket = void 0;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
sendMessage(message) {
|
|
111
|
+
if (!this.socket) {
|
|
112
|
+
throw new Error("Not connected");
|
|
113
|
+
}
|
|
114
|
+
console.log("WebSocket send message", message);
|
|
115
|
+
this.socket.send(toBigIntAwareJson(message));
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* @license
|
|
121
|
+
* Copyright 2025-2026 Open Home Foundation
|
|
122
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
123
|
+
*/
|
|
124
|
+
class MatterError extends Error {}
|
|
125
|
+
class InvalidServerVersion extends MatterError {}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* @license
|
|
129
|
+
* Copyright 2025-2026 Open Home Foundation
|
|
130
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
131
|
+
*/
|
|
132
|
+
class MatterNode {
|
|
133
|
+
constructor(data) {
|
|
134
|
+
this.data = data;
|
|
135
|
+
this.node_id = data.node_id;
|
|
136
|
+
this.date_commissioned = data.date_commissioned;
|
|
137
|
+
this.last_interview = data.last_interview;
|
|
138
|
+
this.interview_version = data.interview_version;
|
|
139
|
+
this.available = data.available;
|
|
140
|
+
this.is_bridge = data.is_bridge;
|
|
141
|
+
this.attributes = data.attributes;
|
|
142
|
+
this.attribute_subscriptions = data.attribute_subscriptions;
|
|
143
|
+
}
|
|
144
|
+
node_id;
|
|
145
|
+
date_commissioned;
|
|
146
|
+
last_interview;
|
|
147
|
+
interview_version;
|
|
148
|
+
available;
|
|
149
|
+
is_bridge;
|
|
150
|
+
attributes;
|
|
151
|
+
attribute_subscriptions;
|
|
152
|
+
get nodeLabel() {
|
|
153
|
+
const label = this.attributes["0/40/5"];
|
|
154
|
+
if (typeof label !== "string") return "";
|
|
155
|
+
if (label.includes("\0\0")) return "";
|
|
156
|
+
return label.trim();
|
|
157
|
+
}
|
|
158
|
+
get vendorName() {
|
|
159
|
+
const value = this.attributes["0/40/1"];
|
|
160
|
+
return typeof value === "string" ? value : "";
|
|
161
|
+
}
|
|
162
|
+
get productName() {
|
|
163
|
+
const value = this.attributes["0/40/3"];
|
|
164
|
+
return typeof value === "string" ? value : "";
|
|
165
|
+
}
|
|
166
|
+
get serialNumber() {
|
|
167
|
+
const value = this.attributes["0/40/15"];
|
|
168
|
+
return typeof value === "string" ? value : "";
|
|
169
|
+
}
|
|
170
|
+
get updateState() {
|
|
171
|
+
const value = this.attributes["0/42/2"];
|
|
172
|
+
return typeof value === "number" ? value : void 0;
|
|
173
|
+
}
|
|
174
|
+
get updateStateProgress() {
|
|
175
|
+
const value = this.attributes["0/42/3"];
|
|
176
|
+
return typeof value === "number" ? value : void 0;
|
|
177
|
+
}
|
|
178
|
+
update(data) {
|
|
179
|
+
return new MatterNode({
|
|
180
|
+
...this.data,
|
|
181
|
+
...data
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* @license
|
|
188
|
+
* Copyright 2025-2026 Open Home Foundation
|
|
189
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
190
|
+
*/
|
|
191
|
+
function toNodeKey(nodeId) {
|
|
192
|
+
return String(nodeId);
|
|
193
|
+
}
|
|
194
|
+
class MatterClient {
|
|
195
|
+
/**
|
|
196
|
+
* Create a new MatterClient.
|
|
197
|
+
* @param url WebSocket URL to connect to
|
|
198
|
+
* @param wsFactory Optional factory function to create WebSocket instances.
|
|
199
|
+
* For Node.js, pass: (url) => new WebSocket(url) from the 'ws' package.
|
|
200
|
+
* For browser, leave undefined to use native WebSocket.
|
|
201
|
+
*/
|
|
202
|
+
constructor(url, wsFactory) {
|
|
203
|
+
this.url = url;
|
|
204
|
+
this.url = url;
|
|
205
|
+
this.connection = new Connection(this.url, wsFactory);
|
|
206
|
+
this.serverBaseAddress = this.url.split("://")[1].split(":")[0] || "";
|
|
207
|
+
}
|
|
208
|
+
connection;
|
|
209
|
+
nodes = {};
|
|
210
|
+
serverBaseAddress;
|
|
211
|
+
/** Whether this client is connected to a production server (optional, for UI purposes) */
|
|
212
|
+
isProduction = false;
|
|
213
|
+
// Using 'unknown' for resolve since the actual types vary by command
|
|
214
|
+
result_futures = {};
|
|
215
|
+
msgId = 0;
|
|
216
|
+
eventListeners = {};
|
|
217
|
+
get serverInfo() {
|
|
218
|
+
return this.connection.serverInfo;
|
|
219
|
+
}
|
|
220
|
+
addEventListener(event, listener) {
|
|
221
|
+
if (!this.eventListeners[event]) {
|
|
222
|
+
this.eventListeners[event] = [];
|
|
223
|
+
}
|
|
224
|
+
this.eventListeners[event].push(listener);
|
|
225
|
+
return () => {
|
|
226
|
+
this.eventListeners[event] = this.eventListeners[event].filter(l => l !== listener);
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
async commissionWithCode(code, networkOnly = true) {
|
|
230
|
+
return await this.sendCommand("commission_with_code", 0, {
|
|
231
|
+
code,
|
|
232
|
+
network_only: networkOnly
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
async setWifiCredentials(ssid, credentials) {
|
|
236
|
+
await this.sendCommand("set_wifi_credentials", 0, {
|
|
237
|
+
ssid,
|
|
238
|
+
credentials
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
async setThreadOperationalDataset(dataset) {
|
|
242
|
+
await this.sendCommand("set_thread_dataset", 0, {
|
|
243
|
+
dataset
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
async openCommissioningWindow(nodeId, timeout, iteration, option, discriminator) {
|
|
247
|
+
return await this.sendCommand("open_commissioning_window", 0, {
|
|
248
|
+
node_id: nodeId,
|
|
249
|
+
timeout,
|
|
250
|
+
iteration,
|
|
251
|
+
option,
|
|
252
|
+
discriminator
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
async discoverCommissionableNodes() {
|
|
256
|
+
return await this.sendCommand("discover_commissionable_nodes", 0, {});
|
|
257
|
+
}
|
|
258
|
+
async getMatterFabrics(nodeId) {
|
|
259
|
+
return await this.sendCommand("get_matter_fabrics", 3, {
|
|
260
|
+
node_id: nodeId
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
async removeMatterFabric(nodeId, fabricIndex) {
|
|
264
|
+
await this.sendCommand("remove_matter_fabric", 3, {
|
|
265
|
+
node_id: nodeId,
|
|
266
|
+
fabric_index: fabricIndex
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
async pingNode(nodeId, attempts = 1) {
|
|
270
|
+
return await this.sendCommand("ping_node", 0, {
|
|
271
|
+
node_id: nodeId,
|
|
272
|
+
attempts
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
async getNodeIPAddresses(nodeId, preferCache, scoped) {
|
|
276
|
+
return await this.sendCommand("get_node_ip_addresses", 8, {
|
|
277
|
+
node_id: nodeId,
|
|
278
|
+
prefer_cache: preferCache,
|
|
279
|
+
scoped
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
async removeNode(nodeId) {
|
|
283
|
+
await this.sendCommand("remove_node", 0, {
|
|
284
|
+
node_id: nodeId
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
async interviewNode(nodeId) {
|
|
288
|
+
await this.sendCommand("interview_node", 0, {
|
|
289
|
+
node_id: nodeId
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
async importTestNode(dump) {
|
|
293
|
+
await this.sendCommand("import_test_node", 0, {
|
|
294
|
+
dump
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
async readAttribute(nodeId, attributePath) {
|
|
298
|
+
return await this.sendCommand("read_attribute", 0, {
|
|
299
|
+
node_id: nodeId,
|
|
300
|
+
attribute_path: attributePath
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
async writeAttribute(nodeId, attributePath, value) {
|
|
304
|
+
return await this.sendCommand("write_attribute", 0, {
|
|
305
|
+
node_id: nodeId,
|
|
306
|
+
attribute_path: attributePath,
|
|
307
|
+
value
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
async checkNodeUpdate(nodeId) {
|
|
311
|
+
return await this.sendCommand("check_node_update", 10, {
|
|
312
|
+
node_id: nodeId
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
async updateNode(nodeId, softwareVersion) {
|
|
316
|
+
await this.sendCommand("update_node", 10, {
|
|
317
|
+
node_id: nodeId,
|
|
318
|
+
software_version: softwareVersion
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
async setACLEntry(nodeId, entry) {
|
|
322
|
+
return await this.sendCommand("set_acl_entry", 0, {
|
|
323
|
+
node_id: nodeId,
|
|
324
|
+
entry
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
async setNodeBinding(nodeId, endpoint, bindings) {
|
|
328
|
+
return await this.sendCommand("set_node_binding", 0, {
|
|
329
|
+
node_id: nodeId,
|
|
330
|
+
endpoint,
|
|
331
|
+
bindings
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
async deviceCommand(nodeId, endpointId, clusterId, commandName, payload = {}) {
|
|
335
|
+
return await this.sendCommand("device_command", 0, {
|
|
336
|
+
node_id: nodeId,
|
|
337
|
+
endpoint_id: endpointId,
|
|
338
|
+
cluster_id: clusterId,
|
|
339
|
+
command_name: commandName,
|
|
340
|
+
payload,
|
|
341
|
+
response_type: null
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
async getNodes(onlyAvailable = false) {
|
|
345
|
+
return await this.sendCommand("get_nodes", 0, {
|
|
346
|
+
only_available: onlyAvailable
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
async getNode(nodeId) {
|
|
350
|
+
return await this.sendCommand("get_node", 0, {
|
|
351
|
+
node_id: nodeId
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
async getVendorNames(filterVendors) {
|
|
355
|
+
return await this.sendCommand("get_vendor_names", 0, {
|
|
356
|
+
filter_vendors: filterVendors
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
async fetchServerInfo() {
|
|
360
|
+
return await this.sendCommand("server_info", 0, {});
|
|
361
|
+
}
|
|
362
|
+
async setDefaultFabricLabel(label) {
|
|
363
|
+
await this.sendCommand("set_default_fabric_label", 0, {
|
|
364
|
+
label
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
sendCommand(command, require_schema = void 0, args) {
|
|
368
|
+
if (require_schema && this.serverInfo.schema_version < require_schema) {
|
|
369
|
+
throw new InvalidServerVersion(`Command not available due to incompatible server version. Update the Matter Server to a version that supports at least api schema ${require_schema}.`);
|
|
370
|
+
}
|
|
371
|
+
const messageId = ++this.msgId;
|
|
372
|
+
const message = {
|
|
373
|
+
message_id: messageId.toString(),
|
|
374
|
+
command,
|
|
375
|
+
args
|
|
376
|
+
};
|
|
377
|
+
const messagePromise = new Promise((resolve, reject) => {
|
|
378
|
+
this.result_futures[messageId] = {
|
|
379
|
+
resolve,
|
|
380
|
+
reject
|
|
381
|
+
};
|
|
382
|
+
this.connection.sendMessage(message);
|
|
383
|
+
});
|
|
384
|
+
return messagePromise.finally(() => {
|
|
385
|
+
delete this.result_futures[messageId];
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
async connect() {
|
|
389
|
+
if (this.connection.connected) {
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
await this.connection.connect(msg => this._handleIncomingMessage(msg), () => this.fireEvent("connection_lost"));
|
|
393
|
+
}
|
|
394
|
+
disconnect(clearStorage = false) {
|
|
395
|
+
if (this.connection && this.connection.connected) {
|
|
396
|
+
this.connection.disconnect();
|
|
397
|
+
}
|
|
398
|
+
if (clearStorage && typeof localStorage !== "undefined") {
|
|
399
|
+
localStorage.removeItem("matterURL");
|
|
400
|
+
location.reload();
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
async startListening() {
|
|
404
|
+
await this.connect();
|
|
405
|
+
const nodesArray = await this.sendCommand("start_listening", 0, {});
|
|
406
|
+
const nodes = {};
|
|
407
|
+
for (const node of nodesArray) {
|
|
408
|
+
nodes[toNodeKey(node.node_id)] = new MatterNode(node);
|
|
409
|
+
}
|
|
410
|
+
this.nodes = nodes;
|
|
411
|
+
}
|
|
412
|
+
_handleIncomingMessage(msg) {
|
|
413
|
+
if ("event" in msg) {
|
|
414
|
+
this._handleEventMessage(msg);
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
if ("error_code" in msg) {
|
|
418
|
+
const promise = this.result_futures[msg.message_id];
|
|
419
|
+
if (promise) {
|
|
420
|
+
promise.reject(new Error(msg.details));
|
|
421
|
+
delete this.result_futures[msg.message_id];
|
|
422
|
+
}
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
425
|
+
if ("result" in msg) {
|
|
426
|
+
const promise = this.result_futures[msg.message_id];
|
|
427
|
+
if (promise) {
|
|
428
|
+
promise.resolve(msg.result);
|
|
429
|
+
delete this.result_futures[msg.message_id];
|
|
430
|
+
}
|
|
431
|
+
return;
|
|
432
|
+
}
|
|
433
|
+
console.warn("Received message with unknown format", msg);
|
|
434
|
+
}
|
|
435
|
+
_handleEventMessage(event) {
|
|
436
|
+
console.log("Incoming event", event);
|
|
437
|
+
this.onRawEvent(event);
|
|
438
|
+
if (event.event === "node_added") {
|
|
439
|
+
const node = new MatterNode(event.data);
|
|
440
|
+
this.nodes = {
|
|
441
|
+
...this.nodes,
|
|
442
|
+
[toNodeKey(node.node_id)]: node
|
|
443
|
+
};
|
|
444
|
+
this.fireEvent("nodes_changed");
|
|
445
|
+
return;
|
|
446
|
+
}
|
|
447
|
+
if (event.event === "node_removed") {
|
|
448
|
+
delete this.nodes[toNodeKey(event.data)];
|
|
449
|
+
this.nodes = {
|
|
450
|
+
...this.nodes
|
|
451
|
+
};
|
|
452
|
+
this.fireEvent("nodes_changed");
|
|
453
|
+
return;
|
|
454
|
+
}
|
|
455
|
+
if (event.event === "node_updated") {
|
|
456
|
+
const node = new MatterNode(event.data);
|
|
457
|
+
this.nodes = {
|
|
458
|
+
...this.nodes,
|
|
459
|
+
[toNodeKey(node.node_id)]: node
|
|
460
|
+
};
|
|
461
|
+
this.fireEvent("nodes_changed");
|
|
462
|
+
return;
|
|
463
|
+
}
|
|
464
|
+
if (event.event === "attribute_updated") {
|
|
465
|
+
const [nodeId, attributeKey, attributeValue] = event.data;
|
|
466
|
+
const nodeKey = toNodeKey(nodeId);
|
|
467
|
+
const existingNode = this.nodes[nodeKey];
|
|
468
|
+
if (existingNode) {
|
|
469
|
+
const node = new MatterNode(existingNode.data);
|
|
470
|
+
node.attributes[attributeKey] = attributeValue;
|
|
471
|
+
this.nodes = {
|
|
472
|
+
...this.nodes,
|
|
473
|
+
[nodeKey]: node
|
|
474
|
+
};
|
|
475
|
+
this.fireEvent("nodes_changed");
|
|
476
|
+
}
|
|
477
|
+
return;
|
|
478
|
+
}
|
|
479
|
+
if (event.event === "server_info_updated") {
|
|
480
|
+
this.connection.serverInfo = event.data;
|
|
481
|
+
this.fireEvent("server_info_updated");
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
if (event.event === "server_shutdown") {
|
|
485
|
+
this.fireEvent("server_shutdown");
|
|
486
|
+
this.disconnect();
|
|
487
|
+
return;
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
fireEvent(event) {
|
|
491
|
+
const listeners = this.eventListeners[event];
|
|
492
|
+
if (listeners) {
|
|
493
|
+
for (const listener of listeners) {
|
|
494
|
+
listener();
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
/**
|
|
499
|
+
* Hook for subclasses to receive raw events.
|
|
500
|
+
* Override this method to intercept all incoming events.
|
|
501
|
+
* @param event The raw event message
|
|
502
|
+
*/
|
|
503
|
+
onRawEvent(_event) {}
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
/**
|
|
507
|
+
* @license
|
|
508
|
+
* Copyright 2025-2026 Open Home Foundation
|
|
509
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
510
|
+
*/
|
|
511
|
+
async function main() {
|
|
512
|
+
import('./matter-dashboard-app-5UjO1Ik8.js').then(function (n) { return n.s; });
|
|
513
|
+
let url = "";
|
|
514
|
+
const isProductionServer = location.origin.includes(":5580") || location.href.includes("hassio_ingress") || location.href.includes("/api/ingress/");
|
|
515
|
+
if (!isProductionServer) {
|
|
516
|
+
let storageUrl = localStorage.getItem("matterURL");
|
|
517
|
+
if (!storageUrl) {
|
|
518
|
+
const urlParams = new URLSearchParams(window.location.search);
|
|
519
|
+
const suggestedUrl = urlParams.get("url");
|
|
520
|
+
storageUrl = prompt("Enter Websocket URL to a running Matter Server", suggestedUrl || "ws://localhost:5580/ws");
|
|
521
|
+
if (!storageUrl) {
|
|
522
|
+
alert("Unable to connect without URL");
|
|
523
|
+
return;
|
|
524
|
+
}
|
|
525
|
+
if (suggestedUrl) {
|
|
526
|
+
history.pushState({}, "", window.location.pathname);
|
|
527
|
+
}
|
|
528
|
+
localStorage.setItem("matterURL", storageUrl);
|
|
529
|
+
}
|
|
530
|
+
url = storageUrl;
|
|
531
|
+
} else {
|
|
532
|
+
let baseUrl = window.location.origin + window.location.pathname;
|
|
533
|
+
if (baseUrl.endsWith("/")) {
|
|
534
|
+
baseUrl = baseUrl.slice(0, -1);
|
|
535
|
+
}
|
|
536
|
+
url = baseUrl.replace("http", "ws") + "/ws";
|
|
537
|
+
console.log(`Connecting to Matter Server API using url: ${url}`);
|
|
538
|
+
}
|
|
539
|
+
const client = new MatterClient(url);
|
|
540
|
+
client.isProduction = isProductionServer;
|
|
541
|
+
const dashboard = document.createElement("matter-dashboard-app");
|
|
542
|
+
dashboard.client = client;
|
|
543
|
+
document.body.append(dashboard);
|
|
544
|
+
}
|
|
545
|
+
main();
|
|
546
|
+
|
|
547
|
+
export { toBigIntAwareJson as t };
|