Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion src/data/zwave_js.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export interface ZWaveJSClient {

export interface ZWaveJSController {
home_id: string;
node_count: number;
nodes: number[];
}

export interface ZWaveJSNode {
Expand All @@ -28,6 +28,14 @@ export interface ZWaveJSNode {
status: number;
}

export enum NodeStatus {
Unknown,
Asleep,
Awake,
Dead,
Alive,
}

export const nodeStatus = ["unknown", "asleep", "awake", "dead", "alive"];

export const fetchNetworkStatus = (
Expand Down
2 changes: 1 addition & 1 deletion src/dialogs/generic/dialog-box.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ class DialogBox extends LitElement {
open
?scrimClickAction=${confirmPrompt}
?escapeKeyAction=${confirmPrompt}
@closed=${this._dialogClosed}
@closing=${this._dialogClosed}
defaultAction="ignore"
.heading=${this._params.title
? this._params.title
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import "@material/mwc-button/mwc-button";
import { mdiCheckCircle, mdiCircle } from "@mdi/js";
import "@material/mwc-icon-button/mwc-icon-button";
import { mdiCheckCircle, mdiCircle, mdiRefresh } from "@mdi/js";
import {
css,
CSSResultArray,
Expand All @@ -12,11 +13,20 @@ import {
} from "lit-element";
import { classMap } from "lit-html/directives/class-map";
import "../../../../../components/ha-card";
import "../../../../../components/ha-svg-icon";
import "../../../../../components/ha-icon-next";
import { getSignedPath } from "../../../../../data/auth";
import {
fetchNetworkStatus,
fetchNodeStatus,
NodeStatus,
ZWaveJSNetwork,
ZWaveJSNode,
} from "../../../../../data/zwave_js";
import {
showAlertDialog,
showConfirmationDialog,
} from "../../../../../dialogs/generic/show-dialog-box";
import "../../../../../layouts/hass-tabs-subpage";
import { haStyle } from "../../../../../resources/styles";
import type { HomeAssistant, Route } from "../../../../../types";
Expand All @@ -39,6 +49,8 @@ class ZWaveJSConfigDashboard extends LitElement {

@internalProperty() private _network?: ZWaveJSNetwork;

@internalProperty() private _nodes?: ZWaveJSNode[];

@internalProperty() private _status = "unknown";

@internalProperty() private _icon = mdiCircle;
Expand All @@ -57,6 +69,9 @@ class ZWaveJSConfigDashboard extends LitElement {
.route=${this.route}
.tabs=${configTabs}
>
<mwc-icon-button slot="toolbar-icon" @click=${this._fetchData}>
<ha-svg-icon .path=${mdiRefresh}></ha-svg-icon>
</mwc-icon-button>
<ha-config-section .narrow=${this.narrow} .isWide=${this.isWide}>
<div slot="header">
${this.hass.localize("ui.panel.config.zwave_js.dashboard.header")}
Expand Down Expand Up @@ -117,9 +132,10 @@ class ZWaveJSConfigDashboard extends LitElement {
)}:
${this._network.controller.home_id}<br />
${this.hass.localize(
"ui.panel.config.zwave_js.dashboard.node_count"
"ui.panel.config.zwave_js.dashboard.nodes_ready"
)}:
${this._network.controller.node_count}
${this._nodes?.filter((node) => node.ready).length ?? 0} /
${this._network.controller.nodes.length}
</div>
</div>
<div class="card-actions">
Expand Down Expand Up @@ -153,18 +169,36 @@ class ZWaveJSConfigDashboard extends LitElement {
</ha-card>
`
: ``}
<button class="link dump" @click=${this._dumpDebugClicked}>
${this.hass.localize(
"ui.panel.config.zwave_js.dashboard.dump_debug"
)}
</button>
</ha-config-section>
</hass-tabs-subpage>
`;
}

private async _fetchData() {
if (!this.configEntryId) return;
if (!this.configEntryId) {
return;
}
this._network = await fetchNetworkStatus(this.hass!, this.configEntryId);
this._status = this._network.client.state;
if (this._status === "connected") {
this._icon = mdiCheckCircle;
}
this._fetchNodeStatus();
}

private async _fetchNodeStatus() {
if (!this._network) {
return;
}
const nodeStatePromisses = this._network.controller.nodes.map((nodeId) =>
fetchNodeStatus(this.hass, this.configEntryId!, nodeId)
);
this._nodes = await Promise.all(nodeStatePromisses);
}

private async _addNodeClicked() {
Expand All @@ -179,6 +213,65 @@ class ZWaveJSConfigDashboard extends LitElement {
});
}

private async _dumpDebugClicked() {
await this._fetchNodeStatus();

const notReadyNodes = this._nodes?.filter((node) => !node.ready);
const deadNodes = this._nodes?.filter(
(node) => node.status === NodeStatus.Dead
);

if (deadNodes?.length) {
await showAlertDialog(this, {
title: this.hass.localize(
"ui.panel.config.zwave_js.dashboard.dump_dead_nodes_title"
),
text: this.hass.localize(
"ui.panel.config.zwave_js.dashboard.dump_dead_nodes_text"
),
});
}

if (
notReadyNodes?.length &&
notReadyNodes.length !== deadNodes?.length &&
!(await showConfirmationDialog(this, {
title: this.hass.localize(
"ui.panel.config.zwave_js.dashboard.dump_not_ready_title"
),
text: this.hass.localize(
"ui.panel.config.zwave_js.dashboard.dump_not_ready_text"
),
confirmText: this.hass.localize(
"ui.panel.config.zwave_js.dashboard.dump_not_ready_confirm"
),
}))
) {
return;
}

let signedPath: { path: string };
try {
signedPath = await getSignedPath(
this.hass,
`/api/zwave_js/dump/${this.configEntryId}`
);
} catch (err) {
showAlertDialog(this, {
title: "Error",
text: err.error || err.body || err,
});
return;
}

const a = document.createElement("a");
a.href = signedPath.path;
a.download = `zwave_js_dump.jsonl`;
this.shadowRoot!.appendChild(a);
a.click();
this.shadowRoot!.removeChild(a);
}

static get styles(): CSSResultArray {
return [
haStyle,
Expand Down Expand Up @@ -207,15 +300,10 @@ class ZWaveJSConfigDashboard extends LitElement {

.network-status div.heading {
display: flex;
justify-content: center;
align-items: center;
margin-bottom: 16px;
}

.network-status {
text-align: center;
}

.network-status div.heading .icon {
width: 48px;
height: 48px;
Expand All @@ -238,6 +326,12 @@ class ZWaveJSConfigDashboard extends LitElement {
max-width: 600px;
}

button.dump {
width: 100%;
text-align: center;
color: var(--secondary-text-color);
}

[hidden] {
display: none;
}
Expand Down
10 changes: 8 additions & 2 deletions src/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -2401,7 +2401,13 @@
"driver_version": "Driver Version",
"server_version": "Server Version",
"home_id": "Home ID",
"node_count": "Node Count"
"nodes_ready": "Nodes ready",
"dump_debug": "Download a dump of your network to help diagnose issues",
"dump_dead_nodes_title": "Some of your nodes are dead",
"dump_dead_nodes_text": "Some of your nodes didn't respond and are assumed dead. These will not be fully exported.",
"dump_not_ready_title": "Not all nodes are ready yet",
"dump_not_ready_text": "If you create an export while not all nodes are ready, you could miss needed data. Give your network some time to query all nodes. Do you want to continue with the dump?",
"dump_not_ready_confirm": "Download"
},
"device_info": {
"zwave_info": "Z-Wave Info",
Expand Down Expand Up @@ -3318,4 +3324,4 @@
}
}
}
}
}