Initial OZW Node Config Panel (#7377)

This commit is contained in:
Charles Garwood 2020-10-19 05:13:55 -04:00 committed by GitHub
parent 7dac7d757e
commit 1ebf1c00d6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 339 additions and 4 deletions

View File

@ -63,6 +63,16 @@ export interface OZWNetworkStatistics {
retries: number;
}
export interface OZWDeviceConfig {
label: string;
type: string;
value: string | number;
parameter: number;
min: number;
max: number;
help: string;
}
export const nodeQueryStages = [
"ProtocolInfo",
"Probe",
@ -180,6 +190,17 @@ export const fetchOZWNodeMetadata = (
node_id: node_id,
});
export const fetchOZWNodeConfig = (
hass: HomeAssistant,
ozw_instance: number,
node_id: number
): Promise<OZWDeviceConfig[]> =>
hass.callWS({
type: "ozw/get_config_parameters",
ozw_instance: ozw_instance,
node_id: node_id,
});
export const refreshNodeInfo = (
hass: HomeAssistant,
ozw_instance: number,

View File

@ -0,0 +1,274 @@
import "@material/mwc-button/mwc-button";
import "@material/mwc-fab";
import {
css,
CSSResultArray,
customElement,
html,
LitElement,
internalProperty,
property,
TemplateResult,
} from "lit-element";
import { navigate } from "../../../../../common/navigate";
import "../../../../../components/buttons/ha-call-service-button";
import "../../../../../components/ha-card";
import "../../../../../components/ha-icon-next";
import "../../../../../layouts/hass-tabs-subpage";
import { haStyle } from "../../../../../resources/styles";
import type { HomeAssistant, Route } from "../../../../../types";
import "../../../ha-config-section";
import {
fetchOZWNodeStatus,
fetchOZWNodeMetadata,
fetchOZWNodeConfig,
OZWDevice,
OZWDeviceMetaDataResponse,
OZWDeviceConfig,
} from "../../../../../data/ozw";
import { ERR_NOT_FOUND } from "../../../../../data/websocket_api";
import { showOZWRefreshNodeDialog } from "./show-dialog-ozw-refresh-node";
import { ozwNodeTabs } from "./ozw-node-router";
@customElement("ozw-node-config")
class OZWNodeConfig extends LitElement {
@property({ type: Object }) public hass!: HomeAssistant;
@property({ type: Object }) public route!: Route;
@property({ type: Boolean }) public narrow!: boolean;
@property({ type: Boolean }) public isWide!: boolean;
@property() public configEntryId?: string;
@property() public ozwInstance?;
@property() public nodeId?;
@internalProperty() private _node?: OZWDevice;
@internalProperty() private _metadata?: OZWDeviceMetaDataResponse;
@internalProperty() private _config?: OZWDeviceConfig[];
@internalProperty() private _error?: string;
protected firstUpdated() {
if (!this.ozwInstance) {
navigate(this, "/config/ozw/dashboard", true);
} else if (!this.nodeId) {
navigate(this, `/config/ozw/network/${this.ozwInstance}/nodes`, true);
} else {
this._fetchData();
}
}
protected render(): TemplateResult {
if (this._error) {
return html`
<hass-error-screen
.error="${this.hass.localize(
"ui.panel.config.ozw.node." + this._error
)}"
></hass-error-screen>
`;
}
return html`
<hass-tabs-subpage
.hass=${this.hass}
.narrow=${this.narrow}
.route=${this.route}
.tabs=${ozwNodeTabs(this.ozwInstance, this.nodeId)}
>
<ha-config-section .narrow=${this.narrow} .isWide=${this.isWide}>
<div slot="header">
${this.hass.localize("ui.panel.config.ozw.node_config.header")}
</div>
<div slot="introduction">
${this.hass.localize(
"ui.panel.config.ozw.node_config.introduction"
)}
<p>
<em>
${this.hass.localize(
"ui.panel.config.ozw.node_config.help_source"
)}
</em>
</p>
<p>
Note: This panel is currently read-only. The ability to change
values will come in a later update.
</p>
</div>
${this._node
? html`
<ha-card class="content">
<div class="card-content">
<b>
${this._node.node_manufacturer_name}
${this._node.node_product_name} </b
><br />
${this.hass.localize("ui.panel.config.ozw.common.node_id")}:
${this._node.node_id}<br />
${this.hass.localize(
"ui.panel.config.ozw.common.query_stage"
)}:
${this._node.node_query_stage}
${this._metadata?.metadata.ProductManualURL
? html` <a
href="${this._metadata.metadata.ProductManualURL}"
>
<p>
${this.hass.localize(
"ui.panel.config.ozw.node_metadata.product_manual"
)}
</p>
</a>`
: ``}
</div>
<div class="card-actions">
<mwc-button @click=${this._refreshNodeClicked}>
${this.hass.localize(
"ui.panel.config.ozw.refresh_node.button"
)}
</mwc-button>
</div>
</ha-card>
${this._metadata?.metadata.WakeupHelp
? html`
<ha-card
class="content"
header="${this.hass.localize(
"ui.panel.config.ozw.common.wakeup_instructions"
)}"
>
<div class="card-content">
<span class="secondary">
${this.hass.localize(
"ui.panel.config.ozw.node_config.wakeup_help"
)}
</span>
<p>
${this._metadata.metadata.WakeupHelp}
</p>
</div>
</ha-card>
`
: ``}
${this._config
? html`
${this._config.map(
(item) => html`
<ha-card class="content">
<div class="card-content">
<b>${item.label}</b><br />
<span class="secondary">${item.help}</span>
<p>${item.value}</p>
</div>
</ha-card>
`
)}
`
: ``}
`
: ``}
</ha-config-section>
</hass-tabs-subpage>
`;
}
private async _fetchData() {
if (!this.ozwInstance || !this.nodeId) {
return;
}
try {
const nodeProm = fetchOZWNodeStatus(
this.hass!,
this.ozwInstance,
this.nodeId
);
const metadataProm = fetchOZWNodeMetadata(
this.hass!,
this.ozwInstance,
this.nodeId
);
const configProm = fetchOZWNodeConfig(
this.hass!,
this.ozwInstance,
this.nodeId
);
[this._node, this._metadata, this._config] = await Promise.all([
nodeProm,
metadataProm,
configProm,
]);
} catch (err) {
if (err.code === ERR_NOT_FOUND) {
this._error = ERR_NOT_FOUND;
return;
}
throw err;
}
}
private async _refreshNodeClicked() {
showOZWRefreshNodeDialog(this, {
node_id: this.nodeId,
ozw_instance: this.ozwInstance,
});
}
static get styles(): CSSResultArray {
return [
haStyle,
css`
.secondary {
color: var(--secondary-text-color);
font-size: 0.9em;
}
.content {
margin-top: 24px;
}
.sectionHeader {
position: relative;
padding-right: 40px;
}
ha-card {
margin: 0 auto;
max-width: 600px;
}
[hidden] {
display: none;
}
blockquote {
display: block;
background-color: #ddd;
padding: 8px;
margin: 8px 0;
font-size: 0.9em;
}
blockquote em {
font-size: 0.9em;
margin-top: 6px;
}
`,
];
}
}
declare global {
interface HTMLElementTagNameMap {
"ozw-node-config": OZWNodeConfig;
}
}

View File

@ -26,7 +26,7 @@ import {
} from "../../../../../data/ozw";
import { ERR_NOT_FOUND } from "../../../../../data/websocket_api";
import { showOZWRefreshNodeDialog } from "./show-dialog-ozw-refresh-node";
import { ozwNetworkTabs } from "./ozw-network-router";
import { ozwNodeTabs } from "./ozw-node-router";
@customElement("ozw-node-dashboard")
class OZWNodeDashboard extends LitElement {
@ -74,7 +74,7 @@ class OZWNodeDashboard extends LitElement {
.hass=${this.hass}
.narrow=${this.narrow}
.route=${this.route}
.tabs=${ozwNetworkTabs(this.ozwInstance)}
.tabs=${ozwNodeTabs(this.ozwInstance, this.nodeId)}
>
<ha-config-section .narrow=${this.narrow} .isWide=${this.isWide}>
<div slot="header">

View File

@ -1,11 +1,31 @@
import { mdiNetwork, mdiWrench } from "@mdi/js";
import { customElement, property } from "lit-element";
import { navigate } from "../../../../../common/navigate";
import {
HassRouterPage,
RouterOptions,
} from "../../../../../layouts/hass-router-page";
import { PageNavigation } from "../../../../../layouts/hass-tabs-subpage";
import { HomeAssistant } from "../../../../../types";
export const ozwNodeTabs = (
instance: number,
node: number
): PageNavigation[] => {
return [
{
translationKey: "ui.panel.config.ozw.navigation.node.dashboard",
path: `/config/ozw/network/${instance}/node/${node}/dashboard`,
iconPath: mdiNetwork,
},
{
translationKey: "ui.panel.config.ozw.navigation.node.config",
path: `/config/ozw/network/${instance}/node/${node}/config`,
iconPath: mdiWrench,
},
];
};
@customElement("ozw-node-router")
class OZWNodeRouter extends HassRouterPage {
@property({ attribute: false }) public hass!: HomeAssistant;
@ -33,6 +53,11 @@ class OZWNodeRouter extends HassRouterPage {
/* webpackChunkName: "ozw-node-dashboard" */ "./ozw-node-dashboard"
),
},
config: {
tag: "ozw-node-config",
load: () =>
import(/* webpackChunkName: "ozw-node-config" */ "./ozw-node-config"),
},
},
};

View File

@ -1899,7 +1899,9 @@
"ozw_instance": "OpenZWave Instance",
"instance": "Instance",
"controller": "Controller",
"network": "Network"
"network": "Network",
"wakeup_instructions": "Wake-up Instructions",
"query_stage": "Query Stage"
},
"device_info": {
"zwave_info": "Z-Wave Info",
@ -1961,7 +1963,11 @@
"navigation": {
"select_instance": "Select Instance",
"network": "Network",
"nodes": "Nodes"
"nodes": "Nodes",
"node": {
"dashboard": "Dashboard",
"config": "Config"
}
},
"select_instance": {
"header": "Select an OpenZWave Instance",
@ -1985,6 +1991,15 @@
"button": "Node Details",
"not_found": "Node not found"
},
"node_config": {
"header": "Node Configuration",
"introduction": "Manage the different configuration parameters for a Z-Wave node.",
"help_source": "Config parameter descriptions and help text are provided by the OpenZWave project.",
"wakeup_help": "Battery powered nodes must be awake to change their configuration. If the node is not awake, OpenZWave will attempt to update the node's configuration the next time it wakes up, which could be multiple hours (or days) later. Follow these steps to wake up your device:"
},
"node_metadata": {
"product_manual": "Product Manual"
},
"services": {
"add_node": "Add Node",
"remove_node": "Remove Node"