mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-10 02:46:38 +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;
|
||||
}
|
||||
|
||||
export interface ZWaveJSSetRawConfigParamData {
|
||||
type: string;
|
||||
device_id: string;
|
||||
property: number;
|
||||
value: number;
|
||||
value_size: number;
|
||||
value_format: number;
|
||||
}
|
||||
|
||||
export interface ZWaveJSSetConfigParamResult {
|
||||
value_id?: string;
|
||||
status?: string;
|
||||
@ -677,6 +686,36 @@ export const setZwaveNodeConfigParameter = (
|
||||
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 = (
|
||||
hass: HomeAssistant,
|
||||
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 "../../../ha-config-section";
|
||||
import { configTabs } from "./zwave_js-config-router";
|
||||
import "./zwave_js-custom-param";
|
||||
import { showConfirmationDialog } from "../../../../../dialogs/generic/show-dialog-box";
|
||||
import { fireEvent } from "../../../../../common/dom/fire_event";
|
||||
|
||||
@ -193,6 +194,22 @@ class ZWaveJSNodeConfig extends LitElement {
|
||||
)}
|
||||
</ha-progress-button>
|
||||
</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>
|
||||
</hass-tabs-subpage>
|
||||
`;
|
||||
@ -600,6 +617,10 @@ class ZWaveJSNodeConfig extends LitElement {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.custom-config {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.reset {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
|
@ -5020,12 +5020,24 @@
|
||||
"parameter_is_read_only": "This parameter is read-only.",
|
||||
"between_min_max": "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",
|
||||
"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_error": "An error occurred.",
|
||||
"parameter": "Parameter",
|
||||
"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": {
|
||||
"button_label": "Reset to default configuration",
|
||||
"dialog": {
|
||||
|
Loading…
x
Reference in New Issue
Block a user