@matter-server/dashboard 0.7.0-alpha.0-20260512-b404bea → 0.7.0
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/esm/client/client-context.d.ts +3 -0
- package/dist/esm/client/client-context.d.ts.map +1 -1
- package/dist/esm/client/client-context.js +3 -1
- package/dist/esm/client/client-context.js.map +1 -1
- package/dist/esm/client/models/descriptions.js +45 -45
- package/dist/esm/components/avsum-ptz-strip.d.ts +41 -0
- package/dist/esm/components/avsum-ptz-strip.d.ts.map +1 -0
- package/dist/esm/components/avsum-ptz-strip.js +379 -0
- package/dist/esm/components/avsum-ptz-strip.js.map +6 -0
- package/dist/esm/components/dialogs/binding/node-binding-dialog.js +1 -1
- package/dist/esm/components/dialogs/binding/show-node-binding-dialog.d.ts +2 -2
- package/dist/esm/components/dialogs/binding/show-node-binding-dialog.d.ts.map +1 -1
- package/dist/esm/components/dialogs/binding/show-node-binding-dialog.js +1 -2
- package/dist/esm/components/dialogs/binding/show-node-binding-dialog.js.map +1 -1
- package/dist/esm/components/dialogs/commission-node-dialog/commission-node-dialog.d.ts +1 -0
- package/dist/esm/components/dialogs/commission-node-dialog/commission-node-dialog.d.ts.map +1 -1
- package/dist/esm/components/dialogs/commission-node-dialog/commission-node-dialog.js +12 -3
- package/dist/esm/components/dialogs/commission-node-dialog/commission-node-dialog.js.map +1 -1
- package/dist/esm/components/dialogs/commission-node-dialog/show-commission-node-dialog.d.ts +1 -2
- package/dist/esm/components/dialogs/commission-node-dialog/show-commission-node-dialog.d.ts.map +1 -1
- package/dist/esm/components/dialogs/commission-node-dialog/show-commission-node-dialog.js +1 -2
- package/dist/esm/components/dialogs/commission-node-dialog/show-commission-node-dialog.js.map +1 -1
- package/dist/esm/components/dialogs/settings/log-level-dialog.d.ts +0 -2
- package/dist/esm/components/dialogs/settings/log-level-dialog.d.ts.map +1 -1
- package/dist/esm/components/dialogs/settings/log-level-dialog.js +2 -8
- package/dist/esm/components/dialogs/settings/log-level-dialog.js.map +1 -1
- package/dist/esm/components/dialogs/settings/log-level-section.d.ts +2 -1
- package/dist/esm/components/dialogs/settings/log-level-section.d.ts.map +1 -1
- package/dist/esm/components/dialogs/settings/log-level-section.js +10 -2
- package/dist/esm/components/dialogs/settings/log-level-section.js.map +1 -1
- package/dist/esm/components/dialogs/settings/settings-dialog.d.ts +1 -0
- package/dist/esm/components/dialogs/settings/settings-dialog.d.ts.map +1 -1
- package/dist/esm/components/dialogs/settings/settings-dialog.js +8 -2
- package/dist/esm/components/dialogs/settings/settings-dialog.js.map +1 -1
- package/dist/esm/components/dialogs/settings/show-log-level-dialog.d.ts +1 -2
- package/dist/esm/components/dialogs/settings/show-log-level-dialog.d.ts.map +1 -1
- package/dist/esm/components/dialogs/settings/show-log-level-dialog.js +1 -2
- package/dist/esm/components/dialogs/settings/show-log-level-dialog.js.map +1 -1
- package/dist/esm/components/dialogs/settings/show-settings-dialog.d.ts +1 -2
- package/dist/esm/components/dialogs/settings/show-settings-dialog.d.ts.map +1 -1
- package/dist/esm/components/dialogs/settings/show-settings-dialog.js +1 -2
- package/dist/esm/components/dialogs/settings/show-settings-dialog.js.map +1 -1
- package/dist/esm/components/webrtc-stream-view.d.ts +97 -0
- package/dist/esm/components/webrtc-stream-view.d.ts.map +1 -0
- package/dist/esm/components/webrtc-stream-view.js +878 -0
- package/dist/esm/components/webrtc-stream-view.js.map +6 -0
- package/dist/esm/pages/camera-overlay.d.ts +63 -0
- package/dist/esm/pages/camera-overlay.d.ts.map +1 -0
- package/dist/esm/pages/camera-overlay.js +546 -0
- package/dist/esm/pages/camera-overlay.js.map +6 -0
- package/dist/esm/pages/cluster-commands/base-cluster-commands.d.ts +1 -0
- package/dist/esm/pages/cluster-commands/base-cluster-commands.d.ts.map +1 -1
- package/dist/esm/pages/cluster-commands/base-cluster-commands.js +11 -1
- package/dist/esm/pages/cluster-commands/base-cluster-commands.js.map +1 -1
- package/dist/esm/pages/cluster-commands/clusters/avsum-commands.d.ts +38 -0
- package/dist/esm/pages/cluster-commands/clusters/avsum-commands.d.ts.map +1 -0
- package/dist/esm/pages/cluster-commands/clusters/avsum-commands.js +534 -0
- package/dist/esm/pages/cluster-commands/clusters/avsum-commands.js.map +6 -0
- package/dist/esm/pages/cluster-commands/clusters/chime-commands.d.ts +32 -0
- package/dist/esm/pages/cluster-commands/clusters/chime-commands.d.ts.map +1 -0
- package/dist/esm/pages/cluster-commands/clusters/chime-commands.js +261 -0
- package/dist/esm/pages/cluster-commands/clusters/chime-commands.js.map +6 -0
- package/dist/esm/pages/cluster-commands/index.d.ts +2 -0
- package/dist/esm/pages/cluster-commands/index.d.ts.map +1 -1
- package/dist/esm/pages/cluster-commands/index.js +2 -0
- package/dist/esm/pages/cluster-commands/index.js.map +1 -1
- package/dist/esm/pages/components/header.d.ts +1 -0
- package/dist/esm/pages/components/header.d.ts.map +1 -1
- package/dist/esm/pages/components/header.js +10 -3
- package/dist/esm/pages/components/header.js.map +1 -1
- package/dist/esm/pages/components/node-details.d.ts +3 -0
- package/dist/esm/pages/components/node-details.d.ts.map +1 -1
- package/dist/esm/pages/components/node-details.js +34 -4
- package/dist/esm/pages/components/node-details.js.map +1 -1
- package/dist/esm/pages/components/server-details.d.ts +1 -0
- package/dist/esm/pages/components/server-details.d.ts.map +1 -1
- package/dist/esm/pages/components/server-details.js +11 -2
- package/dist/esm/pages/components/server-details.js.map +1 -1
- package/dist/esm/pages/matter-cluster-view.d.ts +1 -0
- package/dist/esm/pages/matter-cluster-view.d.ts.map +1 -1
- package/dist/esm/pages/matter-cluster-view.js +15 -8
- package/dist/esm/pages/matter-cluster-view.js.map +1 -1
- package/dist/esm/pages/matter-dashboard-app.d.ts +3 -1
- package/dist/esm/pages/matter-dashboard-app.d.ts.map +1 -1
- package/dist/esm/pages/matter-dashboard-app.js +12 -16
- package/dist/esm/pages/matter-dashboard-app.js.map +1 -1
- package/dist/esm/pages/matter-endpoint-view.d.ts +2 -1
- package/dist/esm/pages/matter-endpoint-view.d.ts.map +1 -1
- package/dist/esm/pages/matter-endpoint-view.js +17 -3
- package/dist/esm/pages/matter-endpoint-view.js.map +1 -1
- package/dist/esm/pages/matter-network-view.d.ts.map +1 -1
- package/dist/esm/pages/matter-network-view.js +5 -1
- package/dist/esm/pages/matter-network-view.js.map +1 -1
- package/dist/esm/pages/matter-node-view.d.ts +1 -0
- package/dist/esm/pages/matter-node-view.d.ts.map +1 -1
- package/dist/esm/pages/matter-node-view.js +15 -7
- package/dist/esm/pages/matter-node-view.js.map +1 -1
- package/dist/esm/pages/matter-server-view.d.ts +1 -0
- package/dist/esm/pages/matter-server-view.d.ts.map +1 -1
- package/dist/esm/pages/matter-server-view.js +13 -2
- package/dist/esm/pages/matter-server-view.js.map +1 -1
- package/dist/esm/pages/network/network-details.d.ts.map +1 -1
- package/dist/esm/pages/network/network-details.js +0 -3
- package/dist/esm/pages/network/network-details.js.map +1 -1
- package/dist/esm/pages/network/update-connections-dialog.d.ts +1 -0
- package/dist/esm/pages/network/update-connections-dialog.d.ts.map +1 -1
- package/dist/esm/pages/network/update-connections-dialog.js +7 -1
- package/dist/esm/pages/network/update-connections-dialog.js.map +1 -1
- package/dist/esm/util/attribute-shapes.d.ts +11 -0
- package/dist/esm/util/attribute-shapes.d.ts.map +1 -0
- package/dist/esm/util/attribute-shapes.js +37 -0
- package/dist/esm/util/attribute-shapes.js.map +6 -0
- package/dist/esm/util/avsum.d.ts +69 -0
- package/dist/esm/util/avsum.d.ts.map +1 -0
- package/dist/esm/util/avsum.js +150 -0
- package/dist/esm/util/avsum.js.map +6 -0
- package/dist/esm/util/chime.d.ts +20 -0
- package/dist/esm/util/chime.d.ts.map +1 -0
- package/dist/esm/util/chime.js +60 -0
- package/dist/esm/util/chime.js.map +6 -0
- package/dist/web/js/{attribute-write-dialog-DzMWN_T3.js → attribute-write-dialog-DLRP2hlx.js} +1 -1
- package/dist/web/js/{command-invoke-dialog-BhAOXzjX.js → command-invoke-dialog-BcCfT1sn.js} +1 -1
- package/dist/web/js/{commission-node-dialog-DF87YIqR.js → commission-node-dialog-BfldkUxD.js} +16 -8
- package/dist/web/js/{commission-node-existing-DLcWvJTL.js → commission-node-existing-omW-An0J.js} +2 -2
- package/dist/web/js/{commission-node-thread-m2fqED-2.js → commission-node-thread-BZpJIxlI.js} +2 -2
- package/dist/web/js/{commission-node-wifi-PCsot-CX.js → commission-node-wifi-HA2pYTW2.js} +2 -2
- package/dist/web/js/{dialog-box-DiqYXM8c.js → dialog-box-BjDID9j4.js} +1 -1
- package/dist/web/js/{fire_event-BnpND_gK.js → fire_event-CChLgSiV.js} +1 -1
- package/dist/web/js/main.js +39 -1
- package/dist/web/js/{matter-dashboard-app-BZOhBELR.js → matter-dashboard-app-XUWBcruM.js} +8265 -2035
- package/dist/web/js/{node-binding-dialog-B3lVN-FU.js → node-binding-dialog-_yHtf7WP.js} +2 -2
- package/dist/web/js/settings-dialog-BFPfOSOI.js +607 -0
- package/package.json +4 -4
- package/src/client/client-context.ts +1 -0
- package/src/client/models/descriptions.ts +45 -45
- package/src/components/avsum-ptz-strip.ts +388 -0
- package/src/components/dialogs/binding/node-binding-dialog.ts +1 -1
- package/src/components/dialogs/binding/show-node-binding-dialog.ts +2 -3
- package/src/components/dialogs/commission-node-dialog/commission-node-dialog.ts +10 -4
- package/src/components/dialogs/commission-node-dialog/show-commission-node-dialog.ts +1 -4
- package/src/components/dialogs/settings/log-level-dialog.ts +2 -9
- package/src/components/dialogs/settings/log-level-section.ts +11 -4
- package/src/components/dialogs/settings/settings-dialog.ts +8 -3
- package/src/components/dialogs/settings/show-log-level-dialog.ts +1 -4
- package/src/components/dialogs/settings/show-settings-dialog.ts +1 -4
- package/src/components/webrtc-stream-view.ts +999 -0
- package/src/pages/camera-overlay.ts +562 -0
- package/src/pages/cluster-commands/base-cluster-commands.ts +7 -1
- package/src/pages/cluster-commands/clusters/avsum-commands.ts +562 -0
- package/src/pages/cluster-commands/clusters/chime-commands.ts +272 -0
- package/src/pages/cluster-commands/index.ts +2 -0
- package/src/pages/components/header.ts +7 -3
- package/src/pages/components/node-details.ts +33 -3
- package/src/pages/components/server-details.ts +8 -2
- package/src/pages/matter-cluster-view.ts +13 -9
- package/src/pages/matter-dashboard-app.ts +11 -16
- package/src/pages/matter-endpoint-view.ts +13 -5
- package/src/pages/matter-network-view.ts +3 -1
- package/src/pages/matter-node-view.ts +9 -7
- package/src/pages/matter-server-view.ts +7 -2
- package/src/pages/network/network-details.ts +0 -3
- package/src/pages/network/update-connections-dialog.ts +6 -1
- package/src/util/attribute-shapes.ts +34 -0
- package/src/util/avsum.ts +212 -0
- package/src/util/chime.ts +82 -0
- package/dist/esm/util/clone_class.d.ts +0 -7
- package/dist/esm/util/clone_class.d.ts.map +0 -1
- package/dist/esm/util/clone_class.js +0 -10
- package/dist/esm/util/clone_class.js.map +0 -6
- package/dist/web/js/settings-dialog-D75IAPKe.js +0 -4039
- package/src/util/clone_class.ts +0 -7
|
@@ -4,20 +4,24 @@
|
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
import { provide } from "@lit/context";
|
|
7
8
|
import "@material/web/button/outlined-button";
|
|
8
9
|
import "@material/web/divider/divider";
|
|
9
10
|
import "@material/web/iconbutton/icon-button";
|
|
10
11
|
import "@material/web/list/list";
|
|
11
12
|
import "@material/web/list/list-item";
|
|
13
|
+
import { consume } from "@lit/context";
|
|
12
14
|
import { MatterClient, MatterNode, isTestNodeId } from "@matter-server/ws-client";
|
|
13
15
|
import { mdiAlertCircleOutline, mdiChevronRight } from "@mdi/js";
|
|
14
16
|
import { LitElement, css, html } from "lit";
|
|
15
17
|
import { customElement, property } from "lit/decorators.js";
|
|
16
18
|
import { guard } from "lit/directives/guard.js";
|
|
19
|
+
import { clientContext, tickContext } from "../client/client-context.js";
|
|
17
20
|
import { DeviceType, clusters, device_types } from "../client/models/descriptions.js";
|
|
18
21
|
import "../components/ha-svg-icon";
|
|
19
22
|
import { formatHex, formatNodeAddress, getEffectiveFabricIndex } from "../util/format_hex.js";
|
|
20
23
|
import { notFoundStyles } from "../util/shared-styles.js";
|
|
24
|
+
import { bindingContext } from "./components/context.js";
|
|
21
25
|
|
|
22
26
|
declare global {
|
|
23
27
|
interface HTMLElementTagNameMap {
|
|
@@ -48,18 +52,23 @@ export function getEndpointDeviceTypes(node: MatterNode, endpoint: number): Devi
|
|
|
48
52
|
|
|
49
53
|
@customElement("matter-endpoint-view")
|
|
50
54
|
class MatterEndpointView extends LitElement {
|
|
55
|
+
@consume({ context: clientContext })
|
|
51
56
|
public client!: MatterClient;
|
|
52
57
|
|
|
58
|
+
@consume({ context: tickContext, subscribe: true })
|
|
59
|
+
protected _tick = 0;
|
|
60
|
+
|
|
53
61
|
@property()
|
|
54
62
|
public node?: MatterNode;
|
|
55
63
|
|
|
64
|
+
@provide({ context: bindingContext })
|
|
56
65
|
@property()
|
|
57
|
-
public endpoint
|
|
66
|
+
public endpoint!: number;
|
|
58
67
|
|
|
59
68
|
override render() {
|
|
60
69
|
if (!this.node || this.endpoint == undefined) {
|
|
61
70
|
return html`
|
|
62
|
-
<dashboard-header title="Not found"
|
|
71
|
+
<dashboard-header title="Not found" backButton="#"></dashboard-header>
|
|
63
72
|
<div class="not-found">
|
|
64
73
|
<ha-svg-icon .path=${mdiAlertCircleOutline}></ha-svg-icon>
|
|
65
74
|
<p>Node or endpoint not found</p>
|
|
@@ -79,12 +88,11 @@ class MatterEndpointView extends LitElement {
|
|
|
79
88
|
<dashboard-header
|
|
80
89
|
.title=${`Node ${this.node.node_id} ${nodeHex} | Endpoint ${this.endpoint}`}
|
|
81
90
|
.backButton=${`#node/${this.node.node_id}`}
|
|
82
|
-
.client=${this.client}
|
|
83
91
|
></dashboard-header>
|
|
84
92
|
|
|
85
93
|
<!-- node details section -->
|
|
86
94
|
<div class="container">
|
|
87
|
-
<node-details .node=${this.node}
|
|
95
|
+
<node-details .node=${this.node}></node-details>
|
|
88
96
|
</div>
|
|
89
97
|
|
|
90
98
|
<!-- Endpoint clusters listing -->
|
|
@@ -104,7 +112,7 @@ class MatterEndpointView extends LitElement {
|
|
|
104
112
|
</div>
|
|
105
113
|
</md-list-item>
|
|
106
114
|
${guard([this.node?.attributes.length], () =>
|
|
107
|
-
getUniqueClusters(this.node!, this.endpoint
|
|
115
|
+
getUniqueClusters(this.node!, this.endpoint).map(cluster => {
|
|
108
116
|
return html`
|
|
109
117
|
<md-list-item
|
|
110
118
|
type="link"
|
|
@@ -4,10 +4,12 @@
|
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
import { consume } from "@lit/context";
|
|
7
8
|
import type { MatterClient, MatterNode } from "@matter-server/ws-client";
|
|
8
9
|
import { mdiEyeOff, mdiFitToScreen, mdiMagnifyMinus, mdiMagnifyPlus, mdiPause, mdiPlay } from "@mdi/js";
|
|
9
10
|
import { css, html, LitElement } from "lit";
|
|
10
11
|
import { customElement, property, query, state } from "lit/decorators.js";
|
|
12
|
+
import { clientContext } from "../client/client-context.js";
|
|
11
13
|
import "../components/ha-svg-icon";
|
|
12
14
|
import { reducedMotionStyles } from "../util/shared-styles.js";
|
|
13
15
|
import "./components/footer";
|
|
@@ -38,6 +40,7 @@ const HIDE_OPTIONS: readonly { key: HideOptionKey; label: string }[] = [
|
|
|
38
40
|
|
|
39
41
|
@customElement("matter-network-view")
|
|
40
42
|
class MatterNetworkView extends LitElement {
|
|
43
|
+
@consume({ context: clientContext })
|
|
41
44
|
public client!: MatterClient;
|
|
42
45
|
|
|
43
46
|
@property({ type: Object })
|
|
@@ -426,7 +429,6 @@ class MatterNetworkView extends LitElement {
|
|
|
426
429
|
return html`
|
|
427
430
|
<dashboard-header
|
|
428
431
|
title="Open Home Foundation Matter Server"
|
|
429
|
-
.client=${this.client}
|
|
430
432
|
.activeView=${this.activeView}
|
|
431
433
|
.hasThreadDevices=${this.hasThreadDevices}
|
|
432
434
|
.hasWifiDevices=${this.hasWifiDevices}
|
|
@@ -9,11 +9,13 @@ import "@material/web/divider/divider";
|
|
|
9
9
|
import "@material/web/iconbutton/icon-button";
|
|
10
10
|
import "@material/web/list/list";
|
|
11
11
|
import "@material/web/list/list-item";
|
|
12
|
+
import { consume } from "@lit/context";
|
|
12
13
|
import { isTestNodeId, MatterClient, MatterNode } from "@matter-server/ws-client";
|
|
13
14
|
import { mdiAlertCircleOutline, mdiChevronRight, mdiGraphOutline } from "@mdi/js";
|
|
14
15
|
import { css, html, LitElement } from "lit";
|
|
15
16
|
import { customElement, property } from "lit/decorators.js";
|
|
16
17
|
import { guard } from "lit/directives/guard.js";
|
|
18
|
+
import { clientContext, tickContext } from "../client/client-context.js";
|
|
17
19
|
import "../components/ha-svg-icon";
|
|
18
20
|
import { getDeviceIcon, getEndpointIcon } from "../util/device-icons.js";
|
|
19
21
|
import { formatNodeAddress, getEffectiveFabricIndex } from "../util/format_hex.js";
|
|
@@ -38,15 +40,19 @@ function getUniqueEndpoints(node: MatterNode) {
|
|
|
38
40
|
|
|
39
41
|
@customElement("matter-node-view")
|
|
40
42
|
class MatterNodeView extends LitElement {
|
|
43
|
+
@consume({ context: clientContext })
|
|
41
44
|
public client!: MatterClient;
|
|
42
45
|
|
|
46
|
+
@consume({ context: tickContext, subscribe: true })
|
|
47
|
+
protected _tick = 0;
|
|
48
|
+
|
|
43
49
|
@property()
|
|
44
50
|
public node?: MatterNode;
|
|
45
51
|
|
|
46
52
|
override render() {
|
|
47
53
|
if (!this.node) {
|
|
48
54
|
return html`
|
|
49
|
-
<dashboard-header title="Node not found"
|
|
55
|
+
<dashboard-header title="Node not found" backButton="#"></dashboard-header>
|
|
50
56
|
<div class="not-found">
|
|
51
57
|
<ha-svg-icon .path=${mdiAlertCircleOutline}></ha-svg-icon>
|
|
52
58
|
<p>Node not found</p>
|
|
@@ -70,11 +76,7 @@ class MatterNodeView extends LitElement {
|
|
|
70
76
|
const nodeHex = formatNodeAddress(fabricIndex, this.node.node_id);
|
|
71
77
|
|
|
72
78
|
return html`
|
|
73
|
-
<dashboard-header
|
|
74
|
-
.title=${`Node ${this.node.node_id} ${nodeHex}`}
|
|
75
|
-
.client=${this.client}
|
|
76
|
-
backButton="#"
|
|
77
|
-
></dashboard-header>
|
|
79
|
+
<dashboard-header .title=${`Node ${this.node.node_id} ${nodeHex}`} backButton="#"></dashboard-header>
|
|
78
80
|
|
|
79
81
|
<!-- node details section -->
|
|
80
82
|
<div class="container">
|
|
@@ -90,7 +92,7 @@ class MatterNodeView extends LitElement {
|
|
|
90
92
|
`
|
|
91
93
|
: ""}
|
|
92
94
|
</div>
|
|
93
|
-
<node-details .node=${this.node}
|
|
95
|
+
<node-details .node=${this.node}></node-details>
|
|
94
96
|
</div>
|
|
95
97
|
|
|
96
98
|
<!-- Node Endpoints listing -->
|
|
@@ -8,10 +8,12 @@ import "@material/web/divider/divider";
|
|
|
8
8
|
import "@material/web/iconbutton/icon-button";
|
|
9
9
|
import "@material/web/list/list";
|
|
10
10
|
import "@material/web/list/list-item";
|
|
11
|
+
import { consume } from "@lit/context";
|
|
11
12
|
import { isTestNodeId, MatterClient, MatterNode } from "@matter-server/ws-client";
|
|
12
13
|
import { mdiChevronRight } from "@mdi/js";
|
|
13
14
|
import { css, html, LitElement, nothing } from "lit";
|
|
14
15
|
import { customElement, property } from "lit/decorators.js";
|
|
16
|
+
import { clientContext, tickContext } from "../client/client-context.js";
|
|
15
17
|
import "../components/ha-svg-icon";
|
|
16
18
|
import { getDeviceIcon } from "../util/device-icons.js";
|
|
17
19
|
import { formatNodeAddress } from "../util/format_hex.js";
|
|
@@ -28,8 +30,12 @@ declare global {
|
|
|
28
30
|
|
|
29
31
|
@customElement("matter-server-view")
|
|
30
32
|
class MatterServerView extends LitElement {
|
|
33
|
+
@consume({ context: clientContext })
|
|
31
34
|
public client!: MatterClient;
|
|
32
35
|
|
|
36
|
+
@consume({ context: tickContext, subscribe: true })
|
|
37
|
+
protected _tick = 0;
|
|
38
|
+
|
|
33
39
|
@property()
|
|
34
40
|
public nodes!: MatterClient["nodes"];
|
|
35
41
|
|
|
@@ -59,7 +65,6 @@ class MatterServerView extends LitElement {
|
|
|
59
65
|
return html`
|
|
60
66
|
<dashboard-header
|
|
61
67
|
title="Open Home Foundation Matter Server"
|
|
62
|
-
.client=${this.client}
|
|
63
68
|
.activeView=${this.activeView}
|
|
64
69
|
.hasThreadDevices=${this.hasThreadDevices}
|
|
65
70
|
.hasWifiDevices=${this.hasWifiDevices}
|
|
@@ -67,7 +72,7 @@ class MatterServerView extends LitElement {
|
|
|
67
72
|
|
|
68
73
|
<!-- server details section -->
|
|
69
74
|
<div class="container">
|
|
70
|
-
<server-details
|
|
75
|
+
<server-details></server-details>
|
|
71
76
|
</div>
|
|
72
77
|
|
|
73
78
|
<!-- Nodes listing -->
|
|
@@ -1054,7 +1054,6 @@ export class NetworkDetails extends LitElement {
|
|
|
1054
1054
|
${this._showUpdateDialog
|
|
1055
1055
|
? html`
|
|
1056
1056
|
<update-connections-dialog
|
|
1057
|
-
.client=${this.client}
|
|
1058
1057
|
.nodes=${this.nodes}
|
|
1059
1058
|
selectedNodeType="unknown"
|
|
1060
1059
|
.selectedNodeName=${this._getSelectedNodeName()}
|
|
@@ -1102,7 +1101,6 @@ export class NetworkDetails extends LitElement {
|
|
|
1102
1101
|
${this._showUpdateDialog
|
|
1103
1102
|
? html`
|
|
1104
1103
|
<update-connections-dialog
|
|
1105
|
-
.client=${this.client}
|
|
1106
1104
|
.nodes=${this.nodes}
|
|
1107
1105
|
selectedNodeType="unknown"
|
|
1108
1106
|
.selectedNodeName=${this._getSelectedNodeName()}
|
|
@@ -1180,7 +1178,6 @@ export class NetworkDetails extends LitElement {
|
|
|
1180
1178
|
${this._showUpdateDialog
|
|
1181
1179
|
? html`
|
|
1182
1180
|
<update-connections-dialog
|
|
1183
|
-
.client=${this.client}
|
|
1184
1181
|
.nodes=${this.nodes}
|
|
1185
1182
|
.selectedNodeType=${nodeType}
|
|
1186
1183
|
.selectedNodeName=${this._getSelectedNodeName()}
|
|
@@ -8,10 +8,12 @@ import "@material/web/button/filled-button";
|
|
|
8
8
|
import "@material/web/button/text-button";
|
|
9
9
|
import "@material/web/checkbox/checkbox";
|
|
10
10
|
import "@material/web/dialog/dialog";
|
|
11
|
+
import { consume } from "@lit/context";
|
|
11
12
|
import type { MatterClient, MatterNode } from "@matter-server/ws-client";
|
|
12
13
|
import { mdiLoading } from "@mdi/js";
|
|
13
14
|
import { LitElement, css, html, nothing, svg } from "lit";
|
|
14
15
|
import { customElement, property, state } from "lit/decorators.js";
|
|
16
|
+
import { clientContext, tickContext } from "../../client/client-context.js";
|
|
15
17
|
import { reducedMotionStyles } from "../../util/shared-styles.js";
|
|
16
18
|
import { getNetworkType } from "./network-utils.js";
|
|
17
19
|
|
|
@@ -29,9 +31,12 @@ const WIFI_ATTRIBUTE_PATHS = ["0/54/0", "0/54/3", "0/54/4"]; // BSSID, Channel,
|
|
|
29
31
|
|
|
30
32
|
@customElement("update-connections-dialog")
|
|
31
33
|
export class UpdateConnectionsDialog extends LitElement {
|
|
32
|
-
@
|
|
34
|
+
@consume({ context: clientContext })
|
|
33
35
|
public client!: MatterClient;
|
|
34
36
|
|
|
37
|
+
@consume({ context: tickContext, subscribe: true })
|
|
38
|
+
protected _tick = 0;
|
|
39
|
+
|
|
35
40
|
@property({ type: Object })
|
|
36
41
|
public nodes: Record<string, MatterNode> = {};
|
|
37
42
|
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025-2026 Open Home Foundation
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export function asObject(value: unknown): Record<string, unknown> | null {
|
|
8
|
+
return typeof value === "object" && value !== null ? (value as Record<string, unknown>) : null;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function pickNumber(obj: Record<string, unknown>, ...keys: string[]): number | null {
|
|
12
|
+
for (const k of keys) {
|
|
13
|
+
const v = obj[k];
|
|
14
|
+
if (typeof v === "number" && Number.isFinite(v)) return v;
|
|
15
|
+
}
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function pickString(obj: Record<string, unknown>, key: string): string | null {
|
|
20
|
+
const v = obj[key];
|
|
21
|
+
return typeof v === "string" ? v : null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function extractAttributeValue(attributesData: unknown): unknown {
|
|
25
|
+
const obj = asObject(attributesData);
|
|
26
|
+
if (!obj) return attributesData;
|
|
27
|
+
const vals = Object.values(obj);
|
|
28
|
+
return vals.length > 0 ? vals[0] : null;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function extractAttributeList(attributesData: unknown): unknown[] {
|
|
32
|
+
const val = extractAttributeValue(attributesData);
|
|
33
|
+
return Array.isArray(val) ? val : [];
|
|
34
|
+
}
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025-2026 Open Home Foundation
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { MatterClient, MatterNode } from "@matter-server/ws-client";
|
|
8
|
+
import { asObject, pickNumber, pickString } from "./attribute-shapes.js";
|
|
9
|
+
|
|
10
|
+
/** Camera AV Settings User Level Management cluster (spec 1.5.1 §11.3). */
|
|
11
|
+
export const AVSUM_CLUSTER_ID = 1362; // 0x0552
|
|
12
|
+
|
|
13
|
+
// Attribute IDs (spec §11.3.6).
|
|
14
|
+
const ATTR_MPTZ_POSITION = 0;
|
|
15
|
+
const ATTR_MAX_PRESETS = 1;
|
|
16
|
+
const ATTR_MPTZ_PRESETS = 2;
|
|
17
|
+
const ATTR_DPTZ_STREAMS = 3;
|
|
18
|
+
const ATTR_ZOOM_MAX = 4;
|
|
19
|
+
const ATTR_TILT_MIN = 5;
|
|
20
|
+
const ATTR_TILT_MAX = 6;
|
|
21
|
+
const ATTR_PAN_MIN = 7;
|
|
22
|
+
const ATTR_PAN_MAX = 8;
|
|
23
|
+
const ATTR_MOVEMENT_STATE = 9;
|
|
24
|
+
const ATTR_FEATURE_MAP = 0xfffc;
|
|
25
|
+
|
|
26
|
+
// Feature bits.
|
|
27
|
+
export const AVSUM_FEAT_DPTZ = 1 << 0;
|
|
28
|
+
export const AVSUM_FEAT_MPAN = 1 << 1;
|
|
29
|
+
export const AVSUM_FEAT_MTILT = 1 << 2;
|
|
30
|
+
export const AVSUM_FEAT_MZOOM = 1 << 3;
|
|
31
|
+
export const AVSUM_FEAT_MPRESETS = 1 << 4;
|
|
32
|
+
|
|
33
|
+
export interface AvsumFeatures {
|
|
34
|
+
dptz: boolean;
|
|
35
|
+
mPan: boolean;
|
|
36
|
+
mTilt: boolean;
|
|
37
|
+
mZoom: boolean;
|
|
38
|
+
mPresets: boolean;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface MptzPosition {
|
|
42
|
+
pan: number | null;
|
|
43
|
+
tilt: number | null;
|
|
44
|
+
zoom: number | null;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface MptzRanges {
|
|
48
|
+
panMin: number | null;
|
|
49
|
+
panMax: number | null;
|
|
50
|
+
tiltMin: number | null;
|
|
51
|
+
tiltMax: number | null;
|
|
52
|
+
zoomMax: number | null;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export type MovementState = "idle" | "moving" | "unknown";
|
|
56
|
+
|
|
57
|
+
export interface MptzPreset {
|
|
58
|
+
presetId: number;
|
|
59
|
+
name: string;
|
|
60
|
+
settings: { pan: number | null; tilt: number | null; zoom: number | null };
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export interface DptzStreamEntry {
|
|
64
|
+
videoStreamId: number;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function readAttr(node: MatterNode, endpoint: number, attrId: number): unknown {
|
|
68
|
+
return node.attributes[`${endpoint}/${AVSUM_CLUSTER_ID}/${attrId}`];
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function readFeatures(node: MatterNode, endpoint: number): AvsumFeatures {
|
|
72
|
+
const fm = readAttr(node, endpoint, ATTR_FEATURE_MAP);
|
|
73
|
+
const bits = typeof fm === "number" ? fm : 0;
|
|
74
|
+
return {
|
|
75
|
+
dptz: (bits & AVSUM_FEAT_DPTZ) !== 0,
|
|
76
|
+
mPan: (bits & AVSUM_FEAT_MPAN) !== 0,
|
|
77
|
+
mTilt: (bits & AVSUM_FEAT_MTILT) !== 0,
|
|
78
|
+
mZoom: (bits & AVSUM_FEAT_MZOOM) !== 0,
|
|
79
|
+
mPresets: (bits & AVSUM_FEAT_MPRESETS) !== 0,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function pickFieldNumber(obj: Record<string, unknown>, named: string, tagId: string): number | null {
|
|
84
|
+
return pickNumber(obj, named) ?? pickNumber(obj, tagId);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function readPosition(node: MatterNode, endpoint: number): MptzPosition {
|
|
88
|
+
const obj = asObject(readAttr(node, endpoint, ATTR_MPTZ_POSITION));
|
|
89
|
+
if (!obj) return { pan: null, tilt: null, zoom: null };
|
|
90
|
+
return {
|
|
91
|
+
pan: pickFieldNumber(obj, "pan", "0"),
|
|
92
|
+
tilt: pickFieldNumber(obj, "tilt", "1"),
|
|
93
|
+
zoom: pickFieldNumber(obj, "zoom", "2"),
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function readRanges(node: MatterNode, endpoint: number): MptzRanges {
|
|
98
|
+
const v = (id: number): number | null => {
|
|
99
|
+
const x = readAttr(node, endpoint, id);
|
|
100
|
+
return typeof x === "number" ? x : null;
|
|
101
|
+
};
|
|
102
|
+
return {
|
|
103
|
+
panMin: v(ATTR_PAN_MIN),
|
|
104
|
+
panMax: v(ATTR_PAN_MAX),
|
|
105
|
+
tiltMin: v(ATTR_TILT_MIN),
|
|
106
|
+
tiltMax: v(ATTR_TILT_MAX),
|
|
107
|
+
zoomMax: v(ATTR_ZOOM_MAX),
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export function readMovementState(node: MatterNode, endpoint: number): MovementState {
|
|
112
|
+
const v = readAttr(node, endpoint, ATTR_MOVEMENT_STATE);
|
|
113
|
+
if (v === 0) return "idle";
|
|
114
|
+
if (v === 1) return "moving";
|
|
115
|
+
return "unknown";
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export function readPresets(node: MatterNode, endpoint: number): { items: MptzPreset[]; max: number } {
|
|
119
|
+
const max = readAttr(node, endpoint, ATTR_MAX_PRESETS);
|
|
120
|
+
const raw = readAttr(node, endpoint, ATTR_MPTZ_PRESETS);
|
|
121
|
+
const items = new Array<MptzPreset>();
|
|
122
|
+
if (Array.isArray(raw)) {
|
|
123
|
+
for (const item of raw) {
|
|
124
|
+
const obj = asObject(item);
|
|
125
|
+
if (!obj) continue;
|
|
126
|
+
const presetId = pickFieldNumber(obj, "presetId", "0");
|
|
127
|
+
const name = pickString(obj, "name") ?? pickString(obj, "1");
|
|
128
|
+
const settings = asObject(obj["settings"] ?? obj["2"]);
|
|
129
|
+
if (presetId === null || name === null) continue;
|
|
130
|
+
items.push({
|
|
131
|
+
presetId,
|
|
132
|
+
name,
|
|
133
|
+
settings: {
|
|
134
|
+
pan: settings ? pickFieldNumber(settings, "pan", "0") : null,
|
|
135
|
+
tilt: settings ? pickFieldNumber(settings, "tilt", "1") : null,
|
|
136
|
+
zoom: settings ? pickFieldNumber(settings, "zoom", "2") : null,
|
|
137
|
+
},
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return { items, max: typeof max === "number" ? max : 0 };
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export function readDptzStreams(node: MatterNode, endpoint: number): DptzStreamEntry[] {
|
|
145
|
+
const raw = readAttr(node, endpoint, ATTR_DPTZ_STREAMS);
|
|
146
|
+
if (!Array.isArray(raw)) return [];
|
|
147
|
+
const out = new Array<DptzStreamEntry>();
|
|
148
|
+
for (const item of raw) {
|
|
149
|
+
const obj = asObject(item);
|
|
150
|
+
if (!obj) continue;
|
|
151
|
+
const id = pickFieldNumber(obj, "videoStreamId", "0");
|
|
152
|
+
if (id !== null) out.push({ videoStreamId: id });
|
|
153
|
+
}
|
|
154
|
+
return out;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export async function relativeMove(
|
|
158
|
+
client: MatterClient,
|
|
159
|
+
nodeId: number | bigint,
|
|
160
|
+
endpoint: number,
|
|
161
|
+
delta: { panDelta?: number; tiltDelta?: number; zoomDelta?: number },
|
|
162
|
+
): Promise<void> {
|
|
163
|
+
await client.deviceCommand(nodeId, endpoint, AVSUM_CLUSTER_ID, "MPTZRelativeMove", delta);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export async function moveToPreset(
|
|
167
|
+
client: MatterClient,
|
|
168
|
+
nodeId: number | bigint,
|
|
169
|
+
endpoint: number,
|
|
170
|
+
presetId: number,
|
|
171
|
+
): Promise<void> {
|
|
172
|
+
await client.deviceCommand(nodeId, endpoint, AVSUM_CLUSTER_ID, "MPTZMoveToPreset", { presetID: presetId });
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export async function savePreset(
|
|
176
|
+
client: MatterClient,
|
|
177
|
+
nodeId: number | bigint,
|
|
178
|
+
endpoint: number,
|
|
179
|
+
name: string,
|
|
180
|
+
presetId?: number,
|
|
181
|
+
): Promise<void> {
|
|
182
|
+
const payload: Record<string, unknown> = { name };
|
|
183
|
+
if (presetId !== undefined) payload.presetID = presetId;
|
|
184
|
+
await client.deviceCommand(nodeId, endpoint, AVSUM_CLUSTER_ID, "MPTZSavePreset", payload);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export async function removePreset(
|
|
188
|
+
client: MatterClient,
|
|
189
|
+
nodeId: number | bigint,
|
|
190
|
+
endpoint: number,
|
|
191
|
+
presetId: number,
|
|
192
|
+
): Promise<void> {
|
|
193
|
+
await client.deviceCommand(nodeId, endpoint, AVSUM_CLUSTER_ID, "MPTZRemovePreset", { presetID: presetId });
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
export async function dptzRelativeMove(
|
|
197
|
+
client: MatterClient,
|
|
198
|
+
nodeId: number | bigint,
|
|
199
|
+
endpoint: number,
|
|
200
|
+
streamId: number,
|
|
201
|
+
delta: { deltaX?: number; deltaY?: number; zoomDelta?: number },
|
|
202
|
+
): Promise<void> {
|
|
203
|
+
await client.deviceCommand(nodeId, endpoint, AVSUM_CLUSTER_ID, "DPTZRelativeMove", {
|
|
204
|
+
videoStreamID: streamId,
|
|
205
|
+
...delta,
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
export function hasAvsumOnEndpoint(node: MatterNode, endpoint: number): boolean {
|
|
210
|
+
const prefix = `${endpoint}/${AVSUM_CLUSTER_ID}/`;
|
|
211
|
+
return Object.keys(node.attributes).some(k => k.startsWith(prefix));
|
|
212
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025-2026 Open Home Foundation
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { MatterClient, MatterNode } from "@matter-server/ws-client";
|
|
8
|
+
import { asObject, pickNumber, pickString } from "./attribute-shapes.js";
|
|
9
|
+
|
|
10
|
+
/** Chime cluster (spec 1.5.1 §11.8). */
|
|
11
|
+
export const CHIME_CLUSTER_ID = 1366; // 0x0556
|
|
12
|
+
|
|
13
|
+
const ATTR_INSTALLED_SOUNDS = 0;
|
|
14
|
+
const ATTR_SELECTED_CHIME = 1;
|
|
15
|
+
const ATTR_ENABLED = 2;
|
|
16
|
+
const ATTR_CLUSTER_REVISION = 0xfffd;
|
|
17
|
+
|
|
18
|
+
export interface ChimeSound {
|
|
19
|
+
chimeId: number;
|
|
20
|
+
name: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function readAttr(node: MatterNode, endpoint: number, attrId: number): unknown {
|
|
24
|
+
return node.attributes[`${endpoint}/${CHIME_CLUSTER_ID}/${attrId}`];
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function readSounds(node: MatterNode, endpoint: number): ChimeSound[] {
|
|
28
|
+
const raw = readAttr(node, endpoint, ATTR_INSTALLED_SOUNDS);
|
|
29
|
+
if (!Array.isArray(raw)) return [];
|
|
30
|
+
const out = new Array<ChimeSound>();
|
|
31
|
+
for (const item of raw) {
|
|
32
|
+
const obj = asObject(item);
|
|
33
|
+
if (!obj) continue;
|
|
34
|
+
const id = pickNumber(obj, "chimeId") ?? pickNumber(obj, "0");
|
|
35
|
+
const name = pickString(obj, "name") ?? pickString(obj, "1");
|
|
36
|
+
if (id !== null && name !== null) out.push({ chimeId: id, name });
|
|
37
|
+
}
|
|
38
|
+
return out;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function readSelected(node: MatterNode, endpoint: number): number | null {
|
|
42
|
+
const v = readAttr(node, endpoint, ATTR_SELECTED_CHIME);
|
|
43
|
+
return typeof v === "number" ? v : null;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function readEnabled(node: MatterNode, endpoint: number): boolean {
|
|
47
|
+
const v = readAttr(node, endpoint, ATTR_ENABLED);
|
|
48
|
+
return v === true;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function readRevision(node: MatterNode, endpoint: number): number {
|
|
52
|
+
const v = readAttr(node, endpoint, ATTR_CLUSTER_REVISION);
|
|
53
|
+
return typeof v === "number" ? v : 1;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export async function setEnabled(
|
|
57
|
+
client: MatterClient,
|
|
58
|
+
nodeId: number | bigint,
|
|
59
|
+
endpoint: number,
|
|
60
|
+
enabled: boolean,
|
|
61
|
+
): Promise<void> {
|
|
62
|
+
await client.writeAttribute(nodeId, `${endpoint}/${CHIME_CLUSTER_ID}/${ATTR_ENABLED}`, enabled);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export async function setSelected(
|
|
66
|
+
client: MatterClient,
|
|
67
|
+
nodeId: number | bigint,
|
|
68
|
+
endpoint: number,
|
|
69
|
+
chimeId: number,
|
|
70
|
+
): Promise<void> {
|
|
71
|
+
await client.writeAttribute(nodeId, `${endpoint}/${CHIME_CLUSTER_ID}/${ATTR_SELECTED_CHIME}`, chimeId);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export async function play(
|
|
75
|
+
client: MatterClient,
|
|
76
|
+
nodeId: number | bigint,
|
|
77
|
+
endpoint: number,
|
|
78
|
+
chimeId?: number,
|
|
79
|
+
): Promise<void> {
|
|
80
|
+
const payload = chimeId !== undefined ? { chimeID: chimeId } : {};
|
|
81
|
+
await client.deviceCommand(nodeId, endpoint, CHIME_CLUSTER_ID, "PlayChimeSound", payload);
|
|
82
|
+
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"clone_class.d.ts","sourceRoot":"","sources":["../../../src/util/clone_class.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,eAAO,MAAM,KAAK,SAAU,GAAG,QAAoE,CAAC"}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @license
|
|
3
|
-
* Copyright 2025-2026 Open Home Foundation
|
|
4
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
-
*/
|
|
6
|
-
const clone = (orig) => Object.assign(Object.create(Object.getPrototypeOf(orig)), orig);
|
|
7
|
-
export {
|
|
8
|
-
clone
|
|
9
|
-
};
|
|
10
|
-
//# sourceMappingURL=clone_class.js.map
|