ZwaveJS network visualization

This commit is contained in:
Petar Petrov 2025-06-18 15:00:21 +03:00
parent 154e85eb45
commit 100525735c
3 changed files with 127 additions and 2 deletions

View File

@ -1,4 +1,4 @@
import { mdiServerNetwork, mdiMathLog } from "@mdi/js"; import { mdiServerNetwork, mdiMathLog, mdiNetwork } from "@mdi/js";
import { customElement, property } from "lit/decorators"; import { customElement, property } from "lit/decorators";
import type { RouterOptions } from "../../../../../layouts/hass-router-page"; import type { RouterOptions } from "../../../../../layouts/hass-router-page";
import { HassRouterPage } from "../../../../../layouts/hass-router-page"; import { HassRouterPage } from "../../../../../layouts/hass-router-page";
@ -18,6 +18,11 @@ export const configTabs: PageNavigation[] = [
path: `/config/zwave_js/logs`, path: `/config/zwave_js/logs`,
iconPath: mdiMathLog, iconPath: mdiMathLog,
}, },
{
translationKey: "ui.panel.config.zwave_js.navigation.visualization",
path: `/config/zwave_js/visualization`,
iconPath: mdiNetwork,
},
]; ];
@customElement("zwave_js-config-router") @customElement("zwave_js-config-router")
@ -60,6 +65,10 @@ class ZWaveJSConfigRouter extends HassRouterPage {
tag: "zwave_js-provisioned", tag: "zwave_js-provisioned",
load: () => import("./zwave_js-provisioned"), load: () => import("./zwave_js-provisioned"),
}, },
visualization: {
tag: "zwave_js-network-visualization",
load: () => import("./zwave_js-network-visualization"),
},
}, },
initialLoad: () => this._fetchConfigEntries(), initialLoad: () => this._fetchConfigEntries(),
}; };

View File

@ -0,0 +1,111 @@
import { customElement, property, state } from "lit/decorators";
import { css, html, LitElement, nothing } from "lit";
import memoizeOne from "memoize-one";
import type { HomeAssistant, Route } from "../../../../../types";
import { configTabs } from "./zwave_js-config-router";
import { SubscribeMixin } from "../../../../../mixins/subscribe-mixin";
import type {
NetworkData,
NetworkLink,
NetworkNode,
} from "../../../../../components/chart/ha-network-graph";
import "../../../../../components/chart/ha-network-graph";
import "../../../../../layouts/hass-tabs-subpage";
import { fetchZwaveNetworkStatus } from "../../../../../data/zwave_js";
import { colorVariables } from "../../../../../resources/theme/color.globals";
@customElement("zwave_js-network-visualization")
export class ZWaveJSNetworkVisualization extends SubscribeMixin(LitElement) {
public hass!: HomeAssistant;
@property({ attribute: false }) public route!: Route;
@property({ attribute: "is-wide", type: Boolean }) public isWide = false;
@property({ type: Boolean }) public narrow = false;
@property({ attribute: false }) public configEntryId!: string;
@state() private _data: NetworkData | null = null;
protected async firstUpdated() {
this._data = await this._getNetworkData();
}
protected render() {
if (!this._data) {
return nothing;
}
return html`
<hass-tabs-subpage
.hass=${this.hass}
.narrow=${this.narrow}
.route=${this.route}
.tabs=${configTabs}
>
<ha-network-graph
.hass=${this.hass}
.data=${this._data}
@chart-click=${this._handleChartClick}
></ha-network-graph
></hass-tabs-subpage>
`;
}
private _getNetworkData = memoizeOne(async (): Promise<NetworkData> => {
const nodes: NetworkNode[] = [];
const links: NetworkLink[] = [];
const categories = [
{
name: this.hass.localize(
"ui.panel.config.zwave_js.visualization.controller"
),
symbol: "roundRect",
itemStyle: {
color: colorVariables["primary-color"],
},
},
{
name: this.hass.localize("ui.panel.config.zwave_js.visualization.node"),
symbol: "circle",
itemStyle: {
color: colorVariables["cyan-color"],
},
},
];
const network = await fetchZwaveNetworkStatus(this.hass!, {
entry_id: this.configEntryId,
});
network.controller.nodes.forEach((node) => {
nodes.push({
id: String(node.node_id),
label: String(node.node_id),
fixed: node.is_controller_node,
polarDistance: node.is_controller_node ? 0 : 0.5,
category: node.is_controller_node ? 0 : 1,
});
});
return { nodes, links, categories };
});
private _handleChartClick(_e: CustomEvent) {
// @TODO
}
static get styles() {
return [
css`
ha-network-graph {
height: 100%;
}
`,
];
}
}
declare global {
interface HTMLElementTagNameMap {
"zwave_js-network-visualization": ZWaveJSNetworkVisualization;
}
}

View File

@ -5792,7 +5792,8 @@
"zwave_js": { "zwave_js": {
"navigation": { "navigation": {
"network": "Network", "network": "Network",
"logs": "Logs" "logs": "Logs",
"visualization": "Visualization"
}, },
"common": { "common": {
"network": "Network", "network": "Network",
@ -6246,6 +6247,10 @@
"log_level_changed": "Log Level changed to: {level}", "log_level_changed": "Log Level changed to: {level}",
"download_logs": "Download logs" "download_logs": "Download logs"
}, },
"visualization": {
"controller": "Controller",
"node": "Node"
},
"node_installer": { "node_installer": {
"header": "Installer Settings", "header": "Installer Settings",
"introduction": "Configure your device installer settings.", "introduction": "Configure your device installer settings.",