mirror of
https://github.com/home-assistant/frontend.git
synced 2026-04-02 00:27:49 +01:00
472 lines
18 KiB
TypeScript
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;
|
|
}
|
|
}
|