mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-12 11:56:34 +00:00
Allow GET/SET custom config param in Z-Wave device configuration (#22364)
* Allow GET/SET custom config param in Z-Wave device configuration * update api calls and validation * update imports * fix import * PR review comments * fix import * fix merge error * fix merge
This commit is contained in:
parent
f6cc435f86
commit
52a91d8403
@ -275,6 +275,15 @@ export interface ZWaveJSSetConfigParamData {
|
|||||||
value: string | number;
|
value: string | number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ZWaveJSSetRawConfigParamData {
|
||||||
|
type: string;
|
||||||
|
device_id: string;
|
||||||
|
property: number;
|
||||||
|
value: number;
|
||||||
|
value_size: number;
|
||||||
|
value_format: number;
|
||||||
|
}
|
||||||
|
|
||||||
export interface ZWaveJSSetConfigParamResult {
|
export interface ZWaveJSSetConfigParamResult {
|
||||||
value_id?: string;
|
value_id?: string;
|
||||||
status?: string;
|
status?: string;
|
||||||
@ -677,6 +686,36 @@ export const setZwaveNodeConfigParameter = (
|
|||||||
return hass.callWS(data);
|
return hass.callWS(data);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const setZwaveNodeRawConfigParameter = (
|
||||||
|
hass: HomeAssistant,
|
||||||
|
device_id: string,
|
||||||
|
property: number,
|
||||||
|
value: number,
|
||||||
|
value_size: number,
|
||||||
|
value_format: number
|
||||||
|
): Promise<ZWaveJSSetConfigParamResult> => {
|
||||||
|
const data: ZWaveJSSetRawConfigParamData = {
|
||||||
|
type: "zwave_js/set_raw_config_parameter",
|
||||||
|
device_id,
|
||||||
|
property,
|
||||||
|
value,
|
||||||
|
value_size,
|
||||||
|
value_format,
|
||||||
|
};
|
||||||
|
return hass.callWS(data);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getZwaveNodeRawConfigParameter = (
|
||||||
|
hass: HomeAssistant,
|
||||||
|
device_id: string,
|
||||||
|
property: number
|
||||||
|
): Promise<number> =>
|
||||||
|
hass.callWS({
|
||||||
|
type: "zwave_js/get_raw_config_parameter",
|
||||||
|
device_id,
|
||||||
|
property,
|
||||||
|
});
|
||||||
|
|
||||||
export const reinterviewZwaveNode = (
|
export const reinterviewZwaveNode = (
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
device_id: string,
|
device_id: string,
|
||||||
|
@ -0,0 +1,254 @@
|
|||||||
|
import { LitElement, html, css, type CSSResultGroup, nothing } from "lit";
|
||||||
|
import { customElement, property, state } from "lit/decorators";
|
||||||
|
import { mdiCloseCircle } from "@mdi/js";
|
||||||
|
import "../../../../../components/ha-textfield";
|
||||||
|
import "../../../../../components/ha-select";
|
||||||
|
import "../../../../../components/ha-button";
|
||||||
|
import "../../../../../components/ha-circular-progress";
|
||||||
|
import "../../../../../components/ha-list-item";
|
||||||
|
import type { HomeAssistant } from "../../../../../types";
|
||||||
|
import {
|
||||||
|
getZwaveNodeRawConfigParameter,
|
||||||
|
setZwaveNodeRawConfigParameter,
|
||||||
|
} from "../../../../../data/zwave_js";
|
||||||
|
|
||||||
|
@customElement("zwave_js-custom-param")
|
||||||
|
class ZWaveJSCustomParam extends LitElement {
|
||||||
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
|
@property() public deviceId!: string;
|
||||||
|
|
||||||
|
@state() private _customParamNumber?: number;
|
||||||
|
|
||||||
|
@state() private _valueSize = 1;
|
||||||
|
|
||||||
|
@state() private _value?: number;
|
||||||
|
|
||||||
|
@state() private _valueFormat = 0;
|
||||||
|
|
||||||
|
@state() private _isLoading = false;
|
||||||
|
|
||||||
|
@state() private _error = "";
|
||||||
|
|
||||||
|
protected render() {
|
||||||
|
return html`
|
||||||
|
<div class="custom-config-form">
|
||||||
|
<ha-textfield
|
||||||
|
.label=${this.hass.localize(
|
||||||
|
"ui.panel.config.zwave_js.node_config.parameter"
|
||||||
|
)}
|
||||||
|
.value=${this._customParamNumber ?? ""}
|
||||||
|
@input=${this._customParamNumberChanged}
|
||||||
|
type="number"
|
||||||
|
></ha-textfield>
|
||||||
|
<ha-select
|
||||||
|
.label=${this.hass.localize(
|
||||||
|
"ui.panel.config.zwave_js.node_config.size"
|
||||||
|
)}
|
||||||
|
.value=${String(this._valueSize)}
|
||||||
|
@selected=${this._customValueSizeChanged}
|
||||||
|
>
|
||||||
|
<ha-list-item value="1">1</ha-list-item>
|
||||||
|
<ha-list-item value="2">2</ha-list-item>
|
||||||
|
<ha-list-item value="4">4</ha-list-item>
|
||||||
|
</ha-select>
|
||||||
|
<ha-textfield
|
||||||
|
.label=${this.hass.localize(
|
||||||
|
"ui.panel.config.zwave_js.node_config.value"
|
||||||
|
)}
|
||||||
|
.value=${this._value ?? ""}
|
||||||
|
@input=${this._customValueChanged}
|
||||||
|
type="number"
|
||||||
|
></ha-textfield>
|
||||||
|
<ha-select
|
||||||
|
.label=${this.hass.localize(
|
||||||
|
"ui.panel.config.zwave_js.node_config.format"
|
||||||
|
)}
|
||||||
|
.value=${String(this._valueFormat)}
|
||||||
|
@selected=${this._customValueFormatChanged}
|
||||||
|
>
|
||||||
|
<ha-list-item value="0"
|
||||||
|
>${this.hass.localize(
|
||||||
|
"ui.panel.config.zwave_js.node_config.signed"
|
||||||
|
)}</ha-list-item
|
||||||
|
>
|
||||||
|
<ha-list-item value="1"
|
||||||
|
>${this.hass.localize(
|
||||||
|
"ui.panel.config.zwave_js.node_config.unsigned"
|
||||||
|
)}</ha-list-item
|
||||||
|
>
|
||||||
|
<ha-list-item value="2"
|
||||||
|
>${this.hass.localize(
|
||||||
|
"ui.panel.config.zwave_js.node_config.enumerated"
|
||||||
|
)}</ha-list-item
|
||||||
|
>
|
||||||
|
<ha-list-item value="3"
|
||||||
|
>${this.hass.localize(
|
||||||
|
"ui.panel.config.zwave_js.node_config.bitfield"
|
||||||
|
)}</ha-list-item
|
||||||
|
>
|
||||||
|
</ha-select>
|
||||||
|
</div>
|
||||||
|
<div class="custom-config-buttons">
|
||||||
|
${this._isLoading
|
||||||
|
? html`<ha-circular-progress indeterminate></ha-circular-progress>`
|
||||||
|
: nothing}
|
||||||
|
<ha-button @click=${this._getCustomConfigValue}>
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.zwave_js.node_config.get_value"
|
||||||
|
)}
|
||||||
|
</ha-button>
|
||||||
|
<ha-button @click=${this._setCustomConfigValue}>
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.zwave_js.node_config.set_value"
|
||||||
|
)}
|
||||||
|
</ha-button>
|
||||||
|
</div>
|
||||||
|
<div class="error">
|
||||||
|
${this._error
|
||||||
|
? html`<ha-svg-icon
|
||||||
|
.path=${mdiCloseCircle}
|
||||||
|
class="error-icon"
|
||||||
|
slot="item-icon"
|
||||||
|
></ha-svg-icon
|
||||||
|
><em>${this._error}</em>`
|
||||||
|
: nothing}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _customParamNumberChanged(ev: Event) {
|
||||||
|
this._customParamNumber =
|
||||||
|
Number((ev.target as HTMLInputElement).value) || undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _customValueSizeChanged(ev: Event) {
|
||||||
|
this._valueSize = Number((ev.target as HTMLSelectElement).value) || 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _customValueChanged(ev: Event) {
|
||||||
|
this._value = Number((ev.target as HTMLInputElement).value) || undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _customValueFormatChanged(ev: Event) {
|
||||||
|
this._valueFormat = Number((ev.target as HTMLSelectElement).value) || 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _getCustomConfigValue() {
|
||||||
|
if (this._customParamNumber === undefined) {
|
||||||
|
this._error = this.hass.localize(
|
||||||
|
"ui.panel.config.zwave_js.node_config.error_required",
|
||||||
|
{
|
||||||
|
entity: this.hass.localize(
|
||||||
|
"ui.panel.config.zwave_js.node_config.parameter"
|
||||||
|
),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._error = "";
|
||||||
|
this._isLoading = true;
|
||||||
|
try {
|
||||||
|
const value = await getZwaveNodeRawConfigParameter(
|
||||||
|
this.hass,
|
||||||
|
this.deviceId,
|
||||||
|
this._customParamNumber
|
||||||
|
);
|
||||||
|
this._value = value;
|
||||||
|
} catch (err: any) {
|
||||||
|
this._error = err?.message || "Unknown error";
|
||||||
|
} finally {
|
||||||
|
this._isLoading = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _setCustomConfigValue() {
|
||||||
|
if (this._customParamNumber === undefined) {
|
||||||
|
this._error = this.hass.localize(
|
||||||
|
"ui.panel.config.zwave_js.node_config.error_required",
|
||||||
|
{
|
||||||
|
entity: this.hass.localize(
|
||||||
|
"ui.panel.config.zwave_js.node_config.parameter"
|
||||||
|
),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this._value === undefined) {
|
||||||
|
this._error = this.hass.localize(
|
||||||
|
"ui.panel.config.zwave_js.node_config.error_required",
|
||||||
|
{
|
||||||
|
entity: this.hass.localize(
|
||||||
|
"ui.panel.config.zwave_js.node_config.value"
|
||||||
|
),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._error = "";
|
||||||
|
this._isLoading = true;
|
||||||
|
try {
|
||||||
|
await setZwaveNodeRawConfigParameter(
|
||||||
|
this.hass,
|
||||||
|
this.deviceId,
|
||||||
|
this._customParamNumber,
|
||||||
|
this._value,
|
||||||
|
this._valueSize,
|
||||||
|
this._valueFormat
|
||||||
|
);
|
||||||
|
} catch (err: any) {
|
||||||
|
this._error = err?.message || "Unknown error";
|
||||||
|
} finally {
|
||||||
|
this._isLoading = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles(): CSSResultGroup {
|
||||||
|
return css`
|
||||||
|
.custom-config-form {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 16px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
ha-textfield,
|
||||||
|
ha-select {
|
||||||
|
flex-grow: 1;
|
||||||
|
flex-basis: calc(50% - 8px);
|
||||||
|
min-width: 120px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 681px) {
|
||||||
|
.custom-config-form {
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
ha-textfield,
|
||||||
|
ha-select {
|
||||||
|
flex-basis: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-config-buttons {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error {
|
||||||
|
color: var(--error-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-icon {
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"zwave_js-custom-param": ZWaveJSCustomParam;
|
||||||
|
}
|
||||||
|
}
|
@ -40,6 +40,7 @@ import { haStyle } from "../../../../../resources/styles";
|
|||||||
import type { HomeAssistant, Route } from "../../../../../types";
|
import type { HomeAssistant, Route } from "../../../../../types";
|
||||||
import "../../../ha-config-section";
|
import "../../../ha-config-section";
|
||||||
import { configTabs } from "./zwave_js-config-router";
|
import { configTabs } from "./zwave_js-config-router";
|
||||||
|
import "./zwave_js-custom-param";
|
||||||
import { showConfirmationDialog } from "../../../../../dialogs/generic/show-dialog-box";
|
import { showConfirmationDialog } from "../../../../../dialogs/generic/show-dialog-box";
|
||||||
import { fireEvent } from "../../../../../common/dom/fire_event";
|
import { fireEvent } from "../../../../../common/dom/fire_event";
|
||||||
|
|
||||||
@ -193,6 +194,22 @@ class ZWaveJSNodeConfig extends LitElement {
|
|||||||
)}
|
)}
|
||||||
</ha-progress-button>
|
</ha-progress-button>
|
||||||
</div>
|
</div>
|
||||||
|
<h3>
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.zwave_js.node_config.custom_config"
|
||||||
|
)}
|
||||||
|
</h3>
|
||||||
|
<span class="secondary">
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.zwave_js.node_config.custom_config_description"
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
<ha-card class="custom-config">
|
||||||
|
<zwave_js-custom-param
|
||||||
|
.hass=${this.hass}
|
||||||
|
.deviceId=${this.deviceId}
|
||||||
|
></zwave_js-custom-param>
|
||||||
|
</ha-card>
|
||||||
</ha-config-section>
|
</ha-config-section>
|
||||||
</hass-tabs-subpage>
|
</hass-tabs-subpage>
|
||||||
`;
|
`;
|
||||||
@ -600,6 +617,10 @@ class ZWaveJSNodeConfig extends LitElement {
|
|||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.custom-config {
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
.reset {
|
.reset {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
|
@ -5020,12 +5020,24 @@
|
|||||||
"parameter_is_read_only": "This parameter is read-only.",
|
"parameter_is_read_only": "This parameter is read-only.",
|
||||||
"between_min_max": "Between {min} and {max}",
|
"between_min_max": "Between {min} and {max}",
|
||||||
"error_not_in_range": "Value must be between {min} and {max}",
|
"error_not_in_range": "Value must be between {min} and {max}",
|
||||||
|
"error_required": "{entity} is required",
|
||||||
"error_device_not_found": "Device not found",
|
"error_device_not_found": "Device not found",
|
||||||
"set_param_accepted": "The parameter has been updated.",
|
"set_param_accepted": "The parameter has been updated.",
|
||||||
"set_param_queued": "The parameter change has been queued, and will be updated when the device wakes up.",
|
"set_param_queued": "The parameter change has been queued, and will be updated when the device wakes up.",
|
||||||
"set_param_error": "An error occurred.",
|
"set_param_error": "An error occurred.",
|
||||||
"parameter": "Parameter",
|
"parameter": "Parameter",
|
||||||
"bitmask": "Bitmask",
|
"bitmask": "Bitmask",
|
||||||
|
"size": "Size",
|
||||||
|
"value": "Value",
|
||||||
|
"format": "Format",
|
||||||
|
"custom_config": "Custom configuration",
|
||||||
|
"custom_config_description": "You can use this section to get/set custom configuration parameters for your device. This is useful when working with devices that are not fully supported.",
|
||||||
|
"get_value": "Get value",
|
||||||
|
"set_value": "Set value",
|
||||||
|
"signed": "Signed",
|
||||||
|
"unsigned": "Unsigned",
|
||||||
|
"enumerated": "Enumerated",
|
||||||
|
"bitfield": "Bitfield",
|
||||||
"reset_to_default": {
|
"reset_to_default": {
|
||||||
"button_label": "Reset to default configuration",
|
"button_label": "Reset to default configuration",
|
||||||
"dialog": {
|
"dialog": {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user