Convert zwave-node-config to lit/ts (#3434)

* Convert zwave-node-config to lit/ts

* Add translations

* lint round 1

* lint round 2

* . all the properties and fix missing types

* Clean up bad prettier auto-style

* set header property instead of attribute
This commit is contained in:
Charles Garwood 2019-08-01 11:32:20 -04:00 committed by Paulus Schoutsen
parent 7d90429fa9
commit d9628fd9a2
4 changed files with 432 additions and 378 deletions

View File

@ -11,6 +11,34 @@ export interface ZWaveValue {
poll_intensity: number;
}
export interface ZWaveConfigItem {
key: number;
value: {
data: any;
data_items: any[];
help: string;
label: string;
max: number;
min: number;
type: string;
};
}
export interface ZWaveConfigServiceData {
node_id: number;
parameter: number;
value: number | string;
}
export interface ZWaveNode {
attributes: ZWaveAttributes;
}
export interface ZWaveAttributes {
node_id: number;
wake_up_interval?: number;
}
export const ZWAVE_NETWORK_STATE_STOPPED = 0;
export const ZWAVE_NETWORK_STATE_FAILED = 1;
export const ZWAVE_NETWORK_STATE_STARTED = 5;
@ -26,3 +54,6 @@ export const fetchNetworkStatus = (
export const fetchValues = (hass: HomeAssistant, nodeId: number) =>
hass.callApi<ZWaveValue[]>("GET", `zwave/values/${nodeId}`);
export const fetchNodeConfig = (hass: HomeAssistant, nodeId: number) =>
hass.callApi<ZWaveConfigItem[]>("GET", `zwave/config/${nodeId}`);

View File

@ -1,377 +0,0 @@
import "@polymer/paper-dropdown-menu/paper-dropdown-menu";
import "@polymer/paper-input/paper-input";
import "@polymer/paper-item/paper-item";
import "@polymer/paper-listbox/paper-listbox";
import { html } from "@polymer/polymer/lib/utils/html-tag";
import { PolymerElement } from "@polymer/polymer/polymer-element";
import "../../../components/buttons/ha-call-service-button";
import "../../../components/ha-card";
class ZwaveNodeConfig extends PolymerElement {
static get template() {
return html`
<style include="iron-flex ha-style">
.content {
margin-top: 24px;
}
ha-card {
margin: 0 auto;
max-width: 600px;
}
.device-picker {
@apply --layout-horizontal;
@apply --layout-center-center;
padding-left: 24px;
padding-right: 24px;
padding-bottom: 24px;
}
.help-text {
padding-left: 24px;
padding-right: 24px;
}
</style>
<div class="content">
<ha-card header="Node config options">
<template is="dom-if" if="[[_wakeupNode]]">
<div class="card-actions">
<paper-input
float-label="Wakeup Interval"
type="number"
value="{{_wakeupInput}}"
placeholder="[[_computeGetWakeupValue(selectedNode)]]"
>
<div suffix="">seconds</div>
</paper-input>
<ha-call-service-button
hass="[[hass]]"
domain="zwave"
service="set_wakeup"
service-data="[[_computeWakeupServiceData(_wakeupInput)]]"
>
Set Wakeup
</ha-call-service-button>
</div>
</template>
<div class="device-picker">
<paper-dropdown-menu
label="Config parameter"
dynamic-align=""
class="flex"
>
<paper-listbox
slot="dropdown-content"
selected="{{_selectedConfigParameter}}"
>
<template is="dom-repeat" items="[[config]]" as="state">
<paper-item
>[[_computeSelectCaptionConfigParameter(state)]]</paper-item
>
</template>
</paper-listbox>
</paper-dropdown-menu>
</div>
<template
is="dom-if"
if="[[_isConfigParameterSelected(_selectedConfigParameter, 'List')]]"
>
<div class="device-picker">
<paper-dropdown-menu
label="Config value"
dynamic-align=""
class="flex"
placeholder="{{_loadedConfigValue}}"
>
<paper-listbox
slot="dropdown-content"
selected="{{_selectedConfigValue}}"
>
<template
is="dom-repeat"
items="[[_selectedConfigParameterValues]]"
as="state"
>
<paper-item>[[state]]</paper-item>
</template>
</paper-listbox>
</paper-dropdown-menu>
</div>
</template>
<template
is="dom-if"
if="[[_isConfigParameterSelected(_selectedConfigParameter, 'Byte Short Int')]]"
>
<div class="card-actions">
<paper-input
label="{{_selectedConfigParameterNumValues}}"
type="number"
value="{{_selectedConfigValue}}"
max="{{_configParameterMax}}"
min="{{_configParameterMin}}"
>
</paper-input>
</div>
</template>
<template
is="dom-if"
if="[[_isConfigParameterSelected(_selectedConfigParameter, 'Bool Button')]]"
>
<div class="device-picker">
<paper-dropdown-menu
label="Config value"
class="flex"
dynamic-align=""
placeholder="{{_loadedConfigValue}}"
>
<paper-listbox
slot="dropdown-content"
selected="{{_selectedConfigValue}}"
>
<template
is="dom-repeat"
items="[[_selectedConfigParameterValues]]"
as="state"
>
<paper-item>[[state]]</paper-item>
</template>
</paper-listbox>
</paper-dropdown-menu>
</div>
</template>
<div class="help-text"><span>[[_configValueHelpText]]</span></div>
<template
is="dom-if"
if="[[_isConfigParameterSelected(_selectedConfigParameter, 'Bool Button Byte Short Int List')]]"
>
<div class="card-actions">
<ha-call-service-button
hass="[[hass]]"
domain="zwave"
service="set_config_parameter"
service-data="[[_computeSetConfigParameterServiceData(_selectedConfigValue)]]"
>
Set Config Parameter
</ha-call-service-button>
</div>
</template>
</ha-card>
</div>
`;
}
static get properties() {
return {
hass: Object,
nodes: Array,
selectedNode: {
type: Number,
observer: "_nodesChanged",
},
config: {
type: Array,
value: () => [],
},
_selectedConfigParameter: {
type: Number,
value: -1,
observer: "_selectedConfigParameterChanged",
},
_configParameterMax: {
type: Number,
value: -1,
},
_configParameterMin: {
type: Number,
value: -1,
},
_configValueHelpText: {
type: String,
value: "",
computed: "_computeConfigValueHelp(_selectedConfigParameter)",
},
_selectedConfigParameterType: {
type: String,
value: "",
},
_selectedConfigValue: {
type: Number,
value: -1,
observer: "_computeSetConfigParameterServiceData",
},
_selectedConfigParameterValues: {
type: Array,
value: () => [],
},
_selectedConfigParameterNumValues: {
type: String,
value: "",
},
_loadedConfigValue: {
type: Number,
value: -1,
},
_wakeupInput: Number,
_wakeupNode: {
type: Boolean,
value: false,
},
};
}
ready() {
super.ready();
this.addEventListener("hass-service-called", (ev) =>
this.serviceCalled(ev)
);
}
serviceCalled(ev) {
if (ev.detail.success) {
setTimeout(() => {
this._refreshConfig(this.selectedNode);
}, 5000);
}
}
_nodesChanged() {
if (!this.nodes) return;
this.setProperties({ _selectedConfigParameter: -1 });
this._wakeupNode =
this.nodes[this.selectedNode].attributes.wake_up_interval === 0 ||
this.nodes[this.selectedNode].attributes.wake_up_interval;
if (this._wakeupNode) {
if (this.nodes[this.selectedNode].attributes.wake_up_interval === 0)
this.setProperties({ _wakeupInput: "" });
else {
this.setProperties({
_wakeupInput: this.nodes[this.selectedNode].attributes
.wake_up_interval,
});
}
}
}
_computeGetWakeupValue(selectedNode) {
if (
this.selectedNode === -1 ||
!this.nodes[selectedNode].attributes.wake_up_interval
)
return "unknown";
return this.nodes[selectedNode].attributes.wake_up_interval;
}
_computeWakeupServiceData(wakeupInput) {
return {
node_id: this.nodes[this.selectedNode].attributes.node_id,
value: wakeupInput,
};
}
_computeConfigValueHelp(selectedConfigParameter) {
if (selectedConfigParameter === -1) return "";
const helpText = this.config[selectedConfigParameter].value.help;
if (!helpText) return ["No helptext available"];
return helpText;
}
_computeSetConfigParameterServiceData(selectedConfigValue) {
if (this.selectedNode === -1 || this._selectedConfigParameter === -1)
return -1;
var valueData = null;
if ("Short Byte Int".includes(this._selectedConfigParameterType)) {
valueData = parseInt(selectedConfigValue, 10);
}
if ("Bool Button List".includes(this._selectedConfigParameterType)) {
valueData = this._selectedConfigParameterValues[selectedConfigValue];
}
return {
node_id: this.nodes[this.selectedNode].attributes.node_id,
parameter: this.config[this._selectedConfigParameter].key,
value: valueData,
};
}
_selectedConfigParameterChanged(selectedConfigParameter) {
if (selectedConfigParameter === -1) return;
this.setProperties({
_selectedConfigValue: -1,
_loadedConfigValue: -1,
_selectedConfigParameterValues: [],
});
this.setProperties({
_selectedConfigParameterType: this.config[selectedConfigParameter].value
.type,
_configParameterMax: this.config[selectedConfigParameter].value.max,
_configParameterMin: this.config[selectedConfigParameter].value.min,
_loadedConfigValue: this.config[selectedConfigParameter].value.data,
_configValueHelpText: this.config[selectedConfigParameter].value.help,
});
if ("Short Byte Int".includes(this._selectedConfigParameterType)) {
this.setProperties({
_selectedConfigParameterNumValues: this.config[selectedConfigParameter]
.value.data_items,
_selectedConfigValue: this._loadedConfigValue,
});
}
if ("Bool Button".includes(this._selectedConfigParameterType)) {
this.setProperties({ _selectedConfigParameterValues: ["True", "False"] });
if (this.config[selectedConfigParameter].value.data) {
this.setProperties({ _loadedConfigValue: "True" });
} else this.setProperties({ _loadedConfigValue: "False" });
}
if ("List".includes(this._selectedConfigParameterType)) {
this.setProperties({
_selectedConfigParameterValues: this.config[selectedConfigParameter]
.value.data_items,
});
}
}
_isConfigParameterSelected(selectedConfigParameter, type) {
if (selectedConfigParameter === -1) return false;
if (this.config[selectedConfigParameter].value.type === type) return true;
if (type.includes(this.config[selectedConfigParameter].value.type))
return true;
return false;
}
_computeSelectCaptionConfigParameter(stateObj) {
return `${stateObj.key}: ${stateObj.value.label}`;
}
async _refreshConfig(selectedNode) {
const configData = [];
const config = await this.hass.callApi(
"GET",
`zwave/config/${this.nodes[selectedNode].attributes.node_id}`
);
Object.keys(config).forEach((key) => {
configData.push({
key: key,
value: config[key],
});
});
this.setProperties({ config: configData });
this._selectedConfigParameterChanged(this._selectedConfigParameter);
}
}
customElements.define("zwave-node-config", ZwaveNodeConfig);

View File

@ -0,0 +1,388 @@
import "@polymer/paper-dropdown-menu/paper-dropdown-menu";
import "@polymer/paper-input/paper-input";
import "@polymer/paper-item/paper-item";
import "@polymer/paper-listbox/paper-listbox";
import {
css,
CSSResult,
customElement,
html,
LitElement,
property,
TemplateResult,
PropertyValues,
} from "lit-element";
import { haStyle } from "../../../resources/styles";
import { HomeAssistant } from "../../../types";
import "../../../components/buttons/ha-call-service-button";
import "../../../components/ha-card";
import {
ZWaveConfigItem,
ZWaveNode,
ZWaveConfigServiceData,
fetchNodeConfig,
} from "../../../data/zwave";
@customElement("zwave-node-config")
export class ZwaveNodeConfig extends LitElement {
@property() public hass!: HomeAssistant;
@property() public nodes: ZWaveNode[] = [];
@property() public config: ZWaveConfigItem[] = [];
@property() public selectedNode: number = -1;
@property() private _configItem?: ZWaveConfigItem;
@property() private _wakeupInput: number = -1;
@property() private _selectedConfigParameter: number = -1;
@property() private _selectedConfigValue: number | string = -1;
protected render(): TemplateResult | void {
return html`
<div class="content">
<ha-card
.header=${this.hass!.localize(
"ui.panel.config.zwave.node_config.header"
)}
>
${"wake_up_interval" in this.nodes[this.selectedNode].attributes
? html`
<div class="card-actions">
<paper-input
.floatLabel="${this.hass!.localize(
"ui.panel.config.zwave.common.wakeup_interval"
)}"
type="number"
.value=${this._wakeupInput !== -1
? this._wakeupInput
: this.hass!.localize(
"ui.panel.config.zwave.common.unknown"
)}
@value-changed=${this._onWakeupIntervalChanged}
.placeholder=${this.nodes[this.selectedNode].attributes
.wake_up_interval
? this.nodes[this.selectedNode].attributes
.wake_up_interval
: this.hass!.localize(
"ui.panel.config.zwave.common.unknown"
)}
>
<div suffix>
${this.hass!.localize(
"ui.panel.config.zwave.node_config.seconds"
)}
</div>
</paper-input>
<ha-call-service-button
.hass=${this.hass}
domain="zwave"
service="set_wakeup"
.serviceData=${this._computeWakeupServiceData(
this._wakeupInput
)}
>
${this.hass!.localize(
"ui.panel.config.zwave.node_config.set_wakeup"
)}
</ha-call-service-button>
</div>
`
: ""}
<div class="device-picker">
<paper-dropdown-menu
.label=${this.hass!.localize(
"ui.panel.config.zwave.node_config.config_parameter"
)}
dynamic-align
class="flex"
>
<paper-listbox
slot="dropdown-content"
.selected=${this._selectedConfigParameter}
@iron-select=${this._selectedConfigParameterChanged}
>
${this.config.map(
(state) => html`
<paper-item>
${state.key}: ${state.value.label}
</paper-item>
`
)}
</paper-listbox>
</paper-dropdown-menu>
</div>
${this._configItem
? html`
${this._configItem.value.type === "List"
? html`
<div class="device-picker">
<paper-dropdown-menu
.label=${this.hass!.localize(
"ui.panel.config.zwave.node_config.config_value"
)}
dynamic-align
class="flex"
.placeholder=${this._configItem.value.data}
>
<paper-listbox
slot="dropdown-content"
.selected=${this._configItem.value.data}
@iron-select=${this._configValueSelectChanged}
>
${this._configItem.value.data_items.map(
(state) => html`
<paper-item>${state}</paper-item>
`
)}
</paper-listbox>
</paper-dropdown-menu>
</div>
`
: ""}
${["Byte", "Short", "Int"].includes(this._configItem.value.type)
? html`
<div class="card-actions">
<paper-input
.label=${this._configItem.value.data_items}
type="number"
.value=${this._configItem.value.data}
.max=${this._configItem.value.max}
.min=${this._configItem.value.min}
@value-changed=${this._configValueInputChanged}
>
</paper-input>
</div>
`
: ""}
${["Bool", "Button"].includes(this._configItem.value.type)
? html`
<div class="device-picker">
<paper-dropdown-menu
.label=${this.hass!.localize(
"ui.panel.config.zwave.node_config.config_value"
)}
class="flex"
dynamic-align
.placeholder=${this._configItem.value.data}
>
<paper-listbox
slot="dropdown-content"
.selected=${this._configItem.value.data}
@iron-select=${this._configValueSelectChanged}
>
<paper-item>
${this.hass!.localize(
"ui.panel.config.zwave.node_config.true"
)}
</paper-item>
<paper-item>
${this.hass!.localize(
"ui.panel.config.zwave.node_config.false"
)}
</paper-item>
</paper-listbox>
</paper-dropdown-menu>
</div>
`
: ""}
<div class="help-text">
<span>${this._configItem.value.help}</span>
</div>
${["Bool", "Button", "Byte", "Short", "Int", "List"].includes(
this._configItem.value.type
)
? html`
<div class="card-actions">
<ha-call-service-button
.hass=${this.hass}
domain="zwave"
service="set_config_parameter"
.serviceData=${this._computeSetConfigParameterServiceData()}
>
${this.hass!.localize(
"ui.panel.config.zwave.node_config.set_config_parameter"
)}
</ha-call-service-button>
</div>
`
: ""}
`
: ""}
</ha-card>
</div>
`;
}
static get styles(): CSSResult[] {
return [
haStyle,
css`
.content {
margin-top: 24px;
}
ha-card {
margin: 0 auto;
max-width: 600px;
}
.device-picker {
@apply --layout-horizontal;
@apply --layout-center-center;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
-ms-flex-direction: row;
-webkit-flex-direction: row;
flex-direction: row;
-ms-flex-align: center;
-webkit-align-items: center;
align-items: center;
padding-left: 24px;
padding-right: 24px;
padding-bottom: 24px;
}
.help-text {
padding-left: 24px;
padding-right: 24px;
}
.flex {
-ms-flex: 1 1 0.000000001px;
-webkit-flex: 1;
flex: 1;
-webkit-flex-basis: 0.000000001px;
flex-basis: 0.000000001px;
}
`,
];
}
protected firstUpdated(changedProps: PropertyValues): void {
super.firstUpdated(changedProps);
this.addEventListener("hass-service-called", (ev) =>
this.serviceCalled(ev)
);
}
protected updated(changedProps: PropertyValues): void {
super.updated(changedProps);
if (changedProps.has("selectedNode")) {
this._nodesChanged();
}
}
private serviceCalled(ev): void {
if (ev.detail.success) {
setTimeout(() => {
this._refreshConfig(this.selectedNode);
}, 5000);
}
}
private _nodesChanged(): void {
if (!this.nodes) {
return;
}
this._configItem = undefined;
this._wakeupInput = this.nodes[this.selectedNode].attributes.hasOwnProperty(
"wake_up_interval"
)
? this.nodes[this.selectedNode].attributes.wake_up_interval!
: -1;
}
private _onWakeupIntervalChanged(value: ChangeEvent): void {
this._wakeupInput = value.detail!.value;
}
private _computeWakeupServiceData(wakeupInput: number) {
return {
node_id: this.nodes[this.selectedNode].attributes.node_id,
value: wakeupInput,
};
}
private _computeSetConfigParameterServiceData():
| ZWaveConfigServiceData
| boolean {
if (this.selectedNode === -1 || typeof this._configItem === "undefined") {
return false;
}
let valueData: number | string = "";
if (["Short", "Byte", "Int"].includes(this._configItem!.value.type)) {
valueData =
typeof this._selectedConfigValue === "string"
? parseInt(this._selectedConfigValue, 10)
: this._selectedConfigValue;
}
if (["Bool", "Button", "List"].includes(this._configItem!.value.type)) {
valueData = this._selectedConfigValue;
}
return {
node_id: this.nodes[this.selectedNode].attributes.node_id,
parameter: this._configItem.key,
value: valueData,
};
}
private _selectedConfigParameterChanged(event: ItemSelectedEvent): void {
if (event.target!.selected === -1) {
return;
}
this._selectedConfigParameter = event.target!.selected;
this._configItem = this.config[event.target!.selected];
}
private _configValueSelectChanged(event: ItemSelectedEvent): void {
if (event.target!.selected === -1) {
return;
}
this._selectedConfigValue = event.target!.selectedItem.textContent;
}
private _configValueInputChanged(value: ChangeEvent): void {
this._selectedConfigValue = value.detail!.value;
}
private async _refreshConfig(selectedNode): Promise<void> {
const configData: ZWaveConfigItem[] = [];
const config = await fetchNodeConfig(
this.hass,
this.nodes[selectedNode].attributes.node_id
);
Object.keys(config).forEach((key) => {
configData.push({
key: parseInt(key, 10),
value: config[key],
});
});
this.config = configData;
this._configItem = this.config[this._selectedConfigParameter];
}
}
export interface ChangeEvent {
detail?: {
value?: any;
};
target?: EventTarget;
}
export interface PickerTarget extends EventTarget {
selected: number;
selectedItem?: any;
}
export interface ItemSelectedEvent {
target?: PickerTarget;
}
declare global {
interface HTMLElementTagNameMap {
"zwave-node-config": ZwaveNodeConfig;
}
}

View File

@ -932,7 +932,9 @@
"common": {
"value": "Value",
"instance": "Instance",
"index": "Index"
"index": "Index",
"unknown": "unknown",
"wakeup_interval": "Wakeup Interval"
},
"network_management": {
"header": "Z-Wave Network Management",
@ -946,6 +948,16 @@
"network_started_note_some_queried": "Awake nodes have been queried. Sleeping nodes will be queried when they wake.",
"network_started_note_all_queried": "All nodes have been queried."
},
"node_config": {
"header": "Node Config Options",
"seconds": "seconds",
"set_wakeup": "Set Wakeup Interval",
"config_parameter": "Config Parameter",
"config_value": "Config Value",
"true": "True",
"false": "False",
"set_config_parameter": "Set Config Parameter"
},
"values": {
"header": "Node Values"
},