Add support for disable polling system option (#9316)

This commit is contained in:
Paulus Schoutsen 2021-05-31 15:40:50 -07:00 committed by GitHub
parent a930e2dc75
commit d8bab6aba9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 138 additions and 90 deletions

View File

@ -28,10 +28,13 @@ const createConfigEntry = (
title, title,
source: "zeroconf", source: "zeroconf",
state: "loaded", state: "loaded",
connection_class: "local_push",
supports_options: false, supports_options: false,
supports_unload: true, supports_unload: true,
disabled_by: null, disabled_by: null,
system_options: {
disable_new_entities: false,
disable_polling: false,
},
reason: null, reason: null,
...override, ...override,
}); });
@ -64,6 +67,12 @@ const configPanelEntry = createConfigEntry("Config Panel", {
const optionsFlowEntry = createConfigEntry("Options Flow", { const optionsFlowEntry = createConfigEntry("Options Flow", {
supports_options: true, supports_options: true,
}); });
const disabledPollingEntry = createConfigEntry("Disabled Polling", {
system_options: {
disable_new_entities: false,
disable_polling: true,
},
});
const setupErrorEntry = createConfigEntry("Setup Error", { const setupErrorEntry = createConfigEntry("Setup Error", {
state: "setup_error", state: "setup_error",
}); });
@ -136,6 +145,7 @@ const configEntries: Array<{
{ items: [loadedEntry] }, { items: [loadedEntry] },
{ items: [configPanelEntry] }, { items: [configPanelEntry] },
{ items: [optionsFlowEntry] }, { items: [optionsFlowEntry] },
{ items: [disabledPollingEntry] },
{ items: [nameAsDomainEntry] }, { items: [nameAsDomainEntry] },
{ items: [longNameEntry] }, { items: [longNameEntry] },
{ items: [longNonBreakingNameEntry] }, { items: [longNonBreakingNameEntry] },

View File

@ -12,9 +12,9 @@ export interface ConfigEntry {
| "setup_retry" | "setup_retry"
| "not_loaded" | "not_loaded"
| "failed_unload"; | "failed_unload";
connection_class: string;
supports_options: boolean; supports_options: boolean;
supports_unload: boolean; supports_unload: boolean;
system_options: ConfigEntrySystemOptions;
disabled_by: "user" | null; disabled_by: "user" | null;
reason: string | null; reason: string | null;
} }
@ -25,6 +25,7 @@ export interface ConfigEntryMutableParams {
export interface ConfigEntrySystemOptions { export interface ConfigEntrySystemOptions {
disable_new_entities: boolean; disable_new_entities: boolean;
disable_polling: boolean;
} }
export const getConfigEntries = (hass: HomeAssistant) => export const getConfigEntries = (hass: HomeAssistant) =>
@ -72,21 +73,15 @@ export const enableConfigEntry = (hass: HomeAssistant, configEntryId: string) =>
disabled_by: null, disabled_by: null,
}); });
export const getConfigEntrySystemOptions = (
hass: HomeAssistant,
configEntryId: string
) =>
hass.callWS<ConfigEntrySystemOptions>({
type: "config_entries/system_options/list",
entry_id: configEntryId,
});
export const updateConfigEntrySystemOptions = ( export const updateConfigEntrySystemOptions = (
hass: HomeAssistant, hass: HomeAssistant,
configEntryId: string, configEntryId: string,
params: Partial<ConfigEntrySystemOptions> params: Partial<ConfigEntrySystemOptions>
) => ) =>
hass.callWS({ hass.callWS<{
require_restart: boolean;
system_options: ConfigEntrySystemOptions;
}>({
type: "config_entries/system_options/update", type: "config_entries/system_options/update",
entry_id: configEntryId, entry_id: configEntryId,
...params, ...params,

View File

@ -3,17 +3,14 @@ import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
import { customElement, property, state } from "lit/decorators"; import { customElement, property, state } from "lit/decorators";
import { fireEvent } from "../../common/dom/fire_event"; import { fireEvent } from "../../common/dom/fire_event";
import { computeRTLDirection } from "../../common/util/compute_rtl"; import { computeRTLDirection } from "../../common/util/compute_rtl";
import "../../components/ha-circular-progress";
import "../../components/ha-dialog"; import "../../components/ha-dialog";
import "../../components/ha-formfield"; import "../../components/ha-formfield";
import "../../components/ha-switch"; import "../../components/ha-switch";
import type { HaSwitch } from "../../components/ha-switch"; import type { HaSwitch } from "../../components/ha-switch";
import { import { updateConfigEntrySystemOptions } from "../../data/config_entries";
getConfigEntrySystemOptions,
updateConfigEntrySystemOptions,
} from "../../data/config_entries";
import { haStyleDialog } from "../../resources/styles"; import { haStyleDialog } from "../../resources/styles";
import type { HomeAssistant } from "../../types"; import type { HomeAssistant } from "../../types";
import { showAlertDialog } from "../generic/show-dialog-box";
import { ConfigEntrySystemOptionsDialogParams } from "./show-dialog-config-entry-system-options"; import { ConfigEntrySystemOptionsDialogParams } from "./show-dialog-config-entry-system-options";
@customElement("dialog-config-entry-system-options") @customElement("dialog-config-entry-system-options")
@ -22,12 +19,12 @@ class DialogConfigEntrySystemOptions extends LitElement {
@state() private _disableNewEntities!: boolean; @state() private _disableNewEntities!: boolean;
@state() private _disablePolling!: boolean;
@state() private _error?: string; @state() private _error?: string;
@state() private _params?: ConfigEntrySystemOptionsDialogParams; @state() private _params?: ConfigEntrySystemOptionsDialogParams;
@state() private _loading = false;
@state() private _submitting = false; @state() private _submitting = false;
public async showDialog( public async showDialog(
@ -35,13 +32,8 @@ class DialogConfigEntrySystemOptions extends LitElement {
): Promise<void> { ): Promise<void> {
this._params = params; this._params = params;
this._error = undefined; this._error = undefined;
this._loading = true; this._disableNewEntities = params.entry.system_options.disable_new_entities;
const systemOptions = await getConfigEntrySystemOptions( this._disablePolling = params.entry.system_options.disable_polling;
this.hass,
params.entry.entry_id
);
this._loading = false;
this._disableNewEntities = systemOptions.disable_new_entities;
} }
public closeDialog(): void { public closeDialog(): void {
@ -66,45 +58,57 @@ class DialogConfigEntrySystemOptions extends LitElement {
this._params.entry.domain this._params.entry.domain
)} )}
> >
<div> ${this._error ? html` <div class="error">${this._error}</div> ` : ""}
${this._loading <ha-formfield
? html` .label=${html`<p>
<div class="init-spinner"> ${this.hass.localize(
<ha-circular-progress active></ha-circular-progress> "ui.dialogs.config_entry_system_options.enable_new_entities_label"
</div> )}
` </p>
: html` <p class="secondary">
${this._error ${this.hass.localize(
? html` <div class="error">${this._error}</div> ` "ui.dialogs.config_entry_system_options.enable_new_entities_description",
: ""} "integration",
<div class="form"> this.hass.localize(
<ha-formfield `component.${this._params.entry.domain}.title`
.label=${html`<p> ) || this._params.entry.domain
${this.hass.localize( )}
"ui.dialogs.config_entry_system_options.enable_new_entities_label" </p>`}
)} .dir=${computeRTLDirection(this.hass)}
</p> >
<p class="secondary"> <ha-switch
${this.hass.localize( .checked=${!this._disableNewEntities}
"ui.dialogs.config_entry_system_options.enable_new_entities_description", @change=${this._disableNewEntitiesChanged}
"integration", .disabled=${this._submitting}
this.hass.localize( ></ha-switch>
`component.${this._params.entry.domain}.title` </ha-formfield>
) || this._params.entry.domain ${this._allowUpdatePolling()
)} ? html`
</p>`} <ha-formfield
.dir=${computeRTLDirection(this.hass)} .label=${html`<p>
> ${this.hass.localize(
<ha-switch "ui.dialogs.config_entry_system_options.enable_polling_label"
.checked=${!this._disableNewEntities} )}
@change=${this._disableNewEntitiesChanged} </p>
.disabled=${this._submitting} <p class="secondary">
> ${this.hass.localize(
</ha-switch> "ui.dialogs.config_entry_system_options.enable_polling_description",
</ha-formfield> "integration",
</div> this.hass.localize(
`} `component.${this._params.entry.domain}.title`
</div> ) || this._params.entry.domain
)}
</p>`}
.dir=${computeRTLDirection(this.hass)}
>
<ha-switch
.checked=${!this._disablePolling}
@change=${this._disablePollingChanged}
.disabled=${this._submitting}
></ha-switch>
</ha-formfield>
`
: ""}
<mwc-button <mwc-button
slot="secondaryAction" slot="secondaryAction"
@click=${this.closeDialog} @click=${this.closeDialog}
@ -115,7 +119,7 @@ class DialogConfigEntrySystemOptions extends LitElement {
<mwc-button <mwc-button
slot="primaryAction" slot="primaryAction"
@click="${this._updateEntry}" @click="${this._updateEntry}"
.disabled=${this._submitting || this._loading} .disabled=${this._submitting}
> >
${this.hass.localize("ui.dialogs.config_entry_system_options.update")} ${this.hass.localize("ui.dialogs.config_entry_system_options.update")}
</mwc-button> </mwc-button>
@ -123,21 +127,53 @@ class DialogConfigEntrySystemOptions extends LitElement {
`; `;
} }
private _allowUpdatePolling() {
return (
this._params!.manifest &&
(this._params!.manifest.iot_class === "local_polling" ||
this._params!.manifest.iot_class === "cloud_polling")
);
}
private _disableNewEntitiesChanged(ev: Event): void { private _disableNewEntitiesChanged(ev: Event): void {
this._error = undefined; this._error = undefined;
this._disableNewEntities = !(ev.target as HaSwitch).checked; this._disableNewEntities = !(ev.target as HaSwitch).checked;
} }
private _disablePollingChanged(ev: Event): void {
this._error = undefined;
this._disablePolling = !(ev.target as HaSwitch).checked;
}
private async _updateEntry(): Promise<void> { private async _updateEntry(): Promise<void> {
this._submitting = true; this._submitting = true;
const data: Parameters<typeof updateConfigEntrySystemOptions>[2] = {
disable_new_entities: this._disableNewEntities,
};
if (this._allowUpdatePolling()) {
data.disable_polling = this._disablePolling;
}
try { try {
await updateConfigEntrySystemOptions( const result = await updateConfigEntrySystemOptions(
this.hass, this.hass,
this._params!.entry.entry_id, this._params!.entry.entry_id,
{ data
disable_new_entities: this._disableNewEntities,
}
); );
if (result.require_restart) {
await showAlertDialog(this, {
text: this.hass.localize(
"ui.dialogs.config_entry_system_options.restart_home_assistant"
),
});
}
const curEntry = this._params!.entry;
this._params!.entryUpdated({
...curEntry,
system_options: {
...curEntry.system_options,
...data,
},
});
this._params = undefined; this._params = undefined;
} catch (err) { } catch (err) {
this._error = err.message || "Unknown error"; this._error = err.message || "Unknown error";
@ -150,20 +186,6 @@ class DialogConfigEntrySystemOptions extends LitElement {
return [ return [
haStyleDialog, haStyleDialog,
css` css`
.init-spinner {
padding: 50px 100px;
text-align: center;
}
.form {
padding-top: 6px;
padding-bottom: 24px;
color: var(--primary-text-color);
}
.secondary {
color: var(--secondary-text-color);
}
.error { .error {
color: var(--error-color); color: var(--error-color);
} }

View File

@ -1,12 +1,11 @@
import { fireEvent } from "../../common/dom/fire_event"; import { fireEvent } from "../../common/dom/fire_event";
import { ConfigEntry } from "../../data/config_entries"; import { ConfigEntry } from "../../data/config_entries";
import { IntegrationManifest } from "../../data/integration";
export interface ConfigEntrySystemOptionsDialogParams { export interface ConfigEntrySystemOptionsDialogParams {
entry: ConfigEntry; entry: ConfigEntry;
// updateEntry: ( manifest?: IntegrationManifest;
// updates: Partial<EntityRegistryEntryUpdateParams> entryUpdated(entry: ConfigEntry): void;
// ) => Promise<unknown>;
// removeEntry: () => Promise<boolean>;
} }
export const loadConfigEntrySystemOptionsDialog = () => export const loadConfigEntrySystemOptionsDialog = () =>

View File

@ -110,6 +110,7 @@ export class HaIntegrationCard extends LitElement {
: undefined} : undefined}
.localizedDomainName=${item ? item.localized_domain_name : undefined} .localizedDomainName=${item ? item.localized_domain_name : undefined}
.manifest=${this.manifest} .manifest=${this.manifest}
.configEntry=${item}
> >
${this.items.length > 1 ${this.items.length > 1
? html` ? html`
@ -466,6 +467,11 @@ export class HaIntegrationCard extends LitElement {
private _showSystemOptions(configEntry: ConfigEntry) { private _showSystemOptions(configEntry: ConfigEntry) {
showConfigEntrySystemOptionsDialog(this, { showConfigEntrySystemOptionsDialog(this, {
entry: configEntry, entry: configEntry,
manifest: this.manifest,
entryUpdated: (entry) =>
fireEvent(this, "entry-updated", {
entry,
}),
}); });
} }

View File

@ -1,8 +1,9 @@
import { mdiCloud, mdiPackageVariant } from "@mdi/js"; import { mdiCloud, mdiPackageVariant, mdiSyncOff } from "@mdi/js";
import "@polymer/paper-tooltip/paper-tooltip"; import "@polymer/paper-tooltip/paper-tooltip";
import { css, html, LitElement, TemplateResult } from "lit"; import { css, html, LitElement, TemplateResult } from "lit";
import { customElement, property } from "lit/decorators"; import { customElement, property } from "lit/decorators";
import "../../../components/ha-svg-icon"; import "../../../components/ha-svg-icon";
import { ConfigEntry } from "../../../data/config_entries";
import { domainToName, IntegrationManifest } from "../../../data/integration"; import { domainToName, IntegrationManifest } from "../../../data/integration";
import { HomeAssistant } from "../../../types"; import { HomeAssistant } from "../../../types";
import { brandsUrl } from "../../../util/brands-url"; import { brandsUrl } from "../../../util/brands-url";
@ -21,6 +22,8 @@ export class HaIntegrationHeader extends LitElement {
@property({ attribute: false }) public manifest?: IntegrationManifest; @property({ attribute: false }) public manifest?: IntegrationManifest;
@property({ attribute: false }) public configEntry?: ConfigEntry;
protected render(): TemplateResult { protected render(): TemplateResult {
let primary: string; let primary: string;
let secondary: string | undefined; let secondary: string | undefined;
@ -59,6 +62,15 @@ export class HaIntegrationHeader extends LitElement {
), ),
]); ]);
} }
if (this.configEntry?.system_options.disable_polling) {
icons.push([
mdiSyncOff,
this.hass.localize(
"ui.panel.config.integrations.config_entry.disabled_polling"
),
]);
}
} }
return html` return html`

View File

@ -759,7 +759,10 @@
"config_entry_system_options": { "config_entry_system_options": {
"title": "System Options for {integration}", "title": "System Options for {integration}",
"enable_new_entities_label": "Enable newly added entities.", "enable_new_entities_label": "Enable newly added entities.",
"enable_new_entities_description": "If disabled, newly discovered entities for {integration} will not be automatically added to Home Assistant.", "enable_new_entities_description": "If newly discovered devices for {integration} should be automatically added.",
"enable_polling_label": "Enable polling for updates.",
"enable_polling_description": "If Home Assistant should automatically poll {integration} entities for updates.",
"restart_home_assistant": "You need to restart Home Assistant for your changes to take effect.",
"update": "Update" "update": "Update"
}, },
"zha_reconfigure_device": { "zha_reconfigure_device": {
@ -2182,6 +2185,7 @@
}, },
"provided_by_custom_integration": "Provided by a custom integration", "provided_by_custom_integration": "Provided by a custom integration",
"depends_on_cloud": "Depends on the cloud", "depends_on_cloud": "Depends on the cloud",
"disabled_polling": "Automatic polling for updated data disabled",
"state": { "state": {
"loaded": "Loaded", "loaded": "Loaded",
"setup_error": "Failed to set up", "setup_error": "Failed to set up",