1
0
mirror of https://github.com/home-assistant/frontend.git synced 2026-04-02 00:27:49 +01:00
Files
frontend/src/panels/config/integrations/integration-panels/zha/zha-options-page.ts

472 lines
18 KiB
TypeScript

import type { CSSResultGroup, PropertyValues, TemplateResult } from "lit";
import { css, html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import "../../../../../components/buttons/ha-progress-button";
import "../../../../../components/ha-card";
import "../../../../../components/ha-md-list";
import "../../../../../components/ha-md-list-item";
import "../../../../../components/ha-select";
import "../../../../../components/input/ha-input";
import "../../../../../components/ha-switch";
import type { ZHAConfiguration } from "../../../../../data/zha";
import {
fetchZHAConfiguration,
updateZHAConfiguration,
} from "../../../../../data/zha";
import "../../../../../layouts/hass-subpage";
import { haStyle } from "../../../../../resources/styles";
import type { HomeAssistant, Route } from "../../../../../types";
const PREDEFINED_TIMEOUTS = [1800, 3600, 7200, 21600, 43200, 86400];
@customElement("zha-options-page")
class ZHAOptionsPage extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property({ attribute: false }) public route!: Route;
@property({ type: Boolean }) public narrow = false;
@property({ attribute: "is-wide", type: Boolean }) public isWide = false;
@state() private _configuration?: ZHAConfiguration;
@state() private _customMains = false;
@state() private _customBattery = false;
protected firstUpdated(changedProperties: PropertyValues) {
super.firstUpdated(changedProperties);
if (this.hass) {
this._fetchConfiguration();
}
}
private async _fetchConfiguration(): Promise<void> {
this._configuration = await fetchZHAConfiguration(this.hass!);
const mainsValue = this._configuration.data.zha_options
?.consider_unavailable_mains as number | undefined;
const batteryValue = this._configuration.data.zha_options
?.consider_unavailable_battery as number | undefined;
this._customMains =
mainsValue !== undefined && !PREDEFINED_TIMEOUTS.includes(mainsValue);
this._customBattery =
batteryValue !== undefined && !PREDEFINED_TIMEOUTS.includes(batteryValue);
}
private _getUnavailableTimeoutOptions(defaultSeconds: number) {
const defaultLabel = ` (${this.hass.localize("ui.panel.config.zha.configuration_page.timeout_default")})`;
const options: { value: string; seconds: number; key: string }[] = [
{ value: "1800", seconds: 1800, key: "timeout_30_min" },
{ value: "3600", seconds: 3600, key: "timeout_1_hour" },
{ value: "7200", seconds: 7200, key: "timeout_2_hours" },
{ value: "21600", seconds: 21600, key: "timeout_6_hours" },
{ value: "43200", seconds: 43200, key: "timeout_12_hours" },
{ value: "86400", seconds: 86400, key: "timeout_24_hours" },
];
return [
...options.map((opt) => ({
value: opt.value,
label: this.hass.localize(
`ui.panel.config.zha.configuration_page.${opt.key}`,
{ default: opt.seconds === defaultSeconds ? defaultLabel : "" }
),
})),
{
value: "custom",
label: this.hass.localize(
"ui.panel.config.zha.configuration_page.timeout_custom"
),
},
];
}
private _getUnavailableDropdownValue(
seconds: unknown,
isCustom: boolean
): string {
if (isCustom) {
return "custom";
}
const value = (seconds as number) ?? 7200;
if (PREDEFINED_TIMEOUTS.includes(value)) {
return String(value);
}
return "custom";
}
protected render(): TemplateResult {
return html`
<hass-subpage
.hass=${this.hass}
.narrow=${this.narrow}
.header=${this.hass.localize(
"ui.panel.config.zha.configuration_page.options_title"
)}
back-path="/config/zha/dashboard"
>
<div class="container">
<ha-card>
${this._configuration
? html`
<ha-md-list>
<ha-md-list-item>
<span slot="headline"
>${this.hass.localize(
"ui.panel.config.zha.configuration_page.enable_identify_on_join_label"
)}</span
>
<span slot="supporting-text"
>${this.hass.localize(
"ui.panel.config.zha.configuration_page.enable_identify_on_join_description"
)}</span
>
<ha-switch
slot="end"
.checked=${(this._configuration.data.zha_options
?.enable_identify_on_join as boolean) ?? true}
@change=${this._enableIdentifyOnJoinChanged}
></ha-switch>
</ha-md-list-item>
<ha-md-list-item>
<span slot="headline"
>${this.hass.localize(
"ui.panel.config.zha.configuration_page.default_light_transition_label"
)}</span
>
<span slot="supporting-text"
>${this.hass.localize(
"ui.panel.config.zha.configuration_page.default_light_transition_description"
)}</span
>
<ha-input
slot="end"
type="number"
.value=${String(
(this._configuration.data.zha_options
?.default_light_transition as number) ?? 0
)}
.min=${0}
.step=${0.5}
@change=${this._defaultLightTransitionChanged}
>
<span slot="end">s</span>
</ha-input>
</ha-md-list-item>
<ha-md-list-item>
<span slot="headline"
>${this.hass.localize(
"ui.panel.config.zha.configuration_page.enhanced_light_transition_label"
)}</span
>
<span slot="supporting-text"
>${this.hass.localize(
"ui.panel.config.zha.configuration_page.enhanced_light_transition_description"
)}</span
>
<ha-switch
slot="end"
.checked=${(this._configuration.data.zha_options
?.enhanced_light_transition as boolean) ?? false}
@change=${this._enhancedLightTransitionChanged}
></ha-switch>
</ha-md-list-item>
<ha-md-list-item>
<span slot="headline"
>${this.hass.localize(
"ui.panel.config.zha.configuration_page.light_transitioning_flag_label"
)}</span
>
<span slot="supporting-text"
>${this.hass.localize(
"ui.panel.config.zha.configuration_page.light_transitioning_flag_description"
)}</span
>
<ha-switch
slot="end"
.checked=${(this._configuration.data.zha_options
?.light_transitioning_flag as boolean) ?? true}
@change=${this._lightTransitioningFlagChanged}
></ha-switch>
</ha-md-list-item>
<ha-md-list-item>
<span slot="headline"
>${this.hass.localize(
"ui.panel.config.zha.configuration_page.group_members_assume_state_label"
)}</span
>
<span slot="supporting-text"
>${this.hass.localize(
"ui.panel.config.zha.configuration_page.group_members_assume_state_description"
)}</span
>
<ha-switch
slot="end"
.checked=${(this._configuration.data.zha_options
?.group_members_assume_state as boolean) ?? true}
@change=${this._groupMembersAssumeStateChanged}
></ha-switch>
</ha-md-list-item>
<ha-md-list-item>
<span slot="headline"
>${this.hass.localize(
"ui.panel.config.zha.configuration_page.consider_unavailable_mains_label"
)}</span
>
<span slot="supporting-text"
>${this.hass.localize(
"ui.panel.config.zha.configuration_page.consider_unavailable_mains_description"
)}</span
>
<ha-select
slot="end"
.value=${this._getUnavailableDropdownValue(
this._configuration.data.zha_options
?.consider_unavailable_mains,
this._customMains
)}
.options=${this._getUnavailableTimeoutOptions(7200)}
@selected=${this._mainsUnavailableChanged}
></ha-select>
</ha-md-list-item>
${this._customMains
? html`
<ha-md-list-item>
<ha-input
slot="end"
type="number"
.value=${String(
(this._configuration.data.zha_options
?.consider_unavailable_mains as number) ??
7200
)}
.min=${1}
.step=${1}
@change=${this._customMainsSecondsChanged}
>
<span slot="end">s</span>
</ha-input>
</ha-md-list-item>
`
: nothing}
<ha-md-list-item>
<span slot="headline"
>${this.hass.localize(
"ui.panel.config.zha.configuration_page.consider_unavailable_battery_label"
)}</span
>
<span slot="supporting-text"
>${this.hass.localize(
"ui.panel.config.zha.configuration_page.consider_unavailable_battery_description"
)}</span
>
<ha-select
slot="end"
.value=${this._getUnavailableDropdownValue(
this._configuration.data.zha_options
?.consider_unavailable_battery,
this._customBattery
)}
.options=${this._getUnavailableTimeoutOptions(21600)}
@selected=${this._batteryUnavailableChanged}
></ha-select>
</ha-md-list-item>
${this._customBattery
? html`
<ha-md-list-item>
<ha-input
slot="end"
type="number"
.value=${String(
(this._configuration.data.zha_options
?.consider_unavailable_battery as number) ??
21600
)}
.min=${1}
.step=${1}
@change=${this._customBatterySecondsChanged}
>
<span slot="end">s</span>
</ha-input>
</ha-md-list-item>
`
: nothing}
<ha-md-list-item>
<span slot="headline"
>${this.hass.localize(
"ui.panel.config.zha.configuration_page.enable_mains_startup_polling_label"
)}</span
>
<span slot="supporting-text"
>${this.hass.localize(
"ui.panel.config.zha.configuration_page.enable_mains_startup_polling_description"
)}</span
>
<ha-switch
slot="end"
.checked=${(this._configuration.data.zha_options
?.enable_mains_startup_polling as boolean) ?? true}
@change=${this._enableMainsStartupPollingChanged}
></ha-switch>
</ha-md-list-item>
</ha-md-list>
<div class="card-actions">
<ha-progress-button
appearance="filled"
variant="brand"
@click=${this._updateConfiguration}
>
${this.hass.localize(
"ui.panel.config.zha.configuration_page.update_button"
)}
</ha-progress-button>
</div>
`
: nothing}
</ha-card>
</div>
</hass-subpage>
`;
}
private _enableIdentifyOnJoinChanged(ev: Event): void {
const checked = (ev.target as HTMLInputElement).checked;
this._configuration!.data.zha_options.enable_identify_on_join = checked;
this.requestUpdate();
}
private _enhancedLightTransitionChanged(ev: Event): void {
const checked = (ev.target as HTMLInputElement).checked;
this._configuration!.data.zha_options.enhanced_light_transition = checked;
this.requestUpdate();
}
private _lightTransitioningFlagChanged(ev: Event): void {
const checked = (ev.target as HTMLInputElement).checked;
this._configuration!.data.zha_options.light_transitioning_flag = checked;
this.requestUpdate();
}
private _groupMembersAssumeStateChanged(ev: Event): void {
const checked = (ev.target as HTMLInputElement).checked;
this._configuration!.data.zha_options.group_members_assume_state = checked;
this.requestUpdate();
}
private _enableMainsStartupPollingChanged(ev: Event): void {
const checked = (ev.target as HTMLInputElement).checked;
this._configuration!.data.zha_options.enable_mains_startup_polling =
checked;
this.requestUpdate();
}
private _defaultLightTransitionChanged(ev: Event): void {
const value = Number((ev.target as HTMLInputElement).value);
this._configuration!.data.zha_options.default_light_transition = value;
this.requestUpdate();
}
private _customMainsSecondsChanged(ev: Event): void {
const seconds = Number((ev.target as HTMLInputElement).value);
this._configuration!.data.zha_options.consider_unavailable_mains = seconds;
this.requestUpdate();
}
private _customBatterySecondsChanged(ev: Event): void {
const seconds = Number((ev.target as HTMLInputElement).value);
this._configuration!.data.zha_options.consider_unavailable_battery =
seconds;
this.requestUpdate();
}
private _mainsUnavailableChanged(ev: CustomEvent): void {
const value = ev.detail.value;
if (value === "custom") {
this._customMains = true;
} else {
this._customMains = false;
this._configuration!.data.zha_options.consider_unavailable_mains =
Number(value);
}
this.requestUpdate();
}
private _batteryUnavailableChanged(ev: CustomEvent): void {
const value = ev.detail.value;
if (value === "custom") {
this._customBattery = true;
} else {
this._customBattery = false;
this._configuration!.data.zha_options.consider_unavailable_battery =
Number(value);
}
this.requestUpdate();
}
private async _updateConfiguration(ev: Event): Promise<void> {
const button = ev.currentTarget as HTMLElement & {
progress: boolean;
actionSuccess: () => void;
actionError: () => void;
};
button.progress = true;
try {
await updateZHAConfiguration(this.hass!, this._configuration!.data);
button.actionSuccess();
} catch (_err: any) {
button.actionError();
} finally {
button.progress = false;
}
}
static get styles(): CSSResultGroup {
return [
haStyle,
css`
.container {
padding: var(--ha-space-2) var(--ha-space-4) var(--ha-space-4);
}
ha-card {
max-width: 600px;
margin: auto;
}
ha-md-list {
background: none;
padding: 0;
}
ha-md-list-item {
--md-item-overflow: visible;
}
ha-select,
ha-input {
min-width: 210px;
}
.card-actions {
display: flex;
justify-content: flex-end;
}
@media all and (max-width: 450px) {
ha-select,
ha-input {
min-width: 160px;
width: 160px;
}
}
`,
];
}
}
declare global {
interface HTMLElementTagNameMap {
"zha-options-page": ZHAOptionsPage;
}
}