Add support for input_button / Button Helper (#10974)

Co-authored-by: Zack Barett <arnett.zackary@gmail.com>
This commit is contained in:
Franck Nijhof 2022-01-11 19:24:59 +01:00 committed by GitHub
parent 3bbe1603eb
commit f852208eff
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 320 additions and 0 deletions

View File

@ -27,6 +27,7 @@ import {
mdiFormTextbox,
mdiGasCylinder,
mdiGauge,
mdiGestureTapButton,
mdiGoogleAssistant,
mdiGoogleCirclesCommunities,
mdiHomeAssistant,
@ -83,6 +84,7 @@ export const FIXED_DOMAIN_ICONS = {
homekit: mdiHomeAutomation,
image_processing: mdiImageFilterFrames,
input_boolean: mdiToggleSwitchOutline,
input_button: mdiGestureTapButton,
input_datetime: mdiCalendarClock,
input_number: mdiRayVertex,
input_select: mdiFormatListBulleted,
@ -150,6 +152,7 @@ export const DOMAINS_WITH_CARD = [
"climate",
"cover",
"configurator",
"input_button",
"input_select",
"input_number",
"input_text",
@ -216,6 +219,7 @@ export const DOMAINS_INPUT_ROW = [
"group",
"humidifier",
"input_boolean",
"input_button",
"input_datetime",
"input_number",
"input_select",

View File

@ -119,6 +119,7 @@ export const computeStateDisplay = (
// state of button is a timestamp
if (
domain === "button" ||
domain === "input_button" ||
(domain === "sensor" && stateObj.attributes.device_class === "timestamp")
) {
return formatDateTime(new Date(compareState), locale);

41
src/data/input_button.ts Normal file
View File

@ -0,0 +1,41 @@
import { HomeAssistant } from "../types";
export interface InputButton {
id: string;
name: string;
icon?: string;
}
export interface InputButtonMutableParams {
name: string;
icon: string;
}
export const fetchInputButton = (hass: HomeAssistant) =>
hass.callWS<InputButton[]>({ type: "input_button/list" });
export const createInputButton = (
hass: HomeAssistant,
values: InputButtonMutableParams
) =>
hass.callWS<InputButton>({
type: "input_button/create",
...values,
});
export const updateInputButton = (
hass: HomeAssistant,
id: string,
updates: Partial<InputButtonMutableParams>
) =>
hass.callWS<InputButton>({
type: "input_button/update",
input_button_id: id,
...updates,
});
export const deleteInputButton = (hass: HomeAssistant, id: string) =>
hass.callWS({
type: "input_button/delete",
input_button_id: id,
});

View File

@ -7,4 +7,5 @@ export const PLATFORMS_WITH_SETTINGS_TAB = {
input_datetime: "entity-settings-helper-tab",
counter: "entity-settings-helper-tab",
timer: "entity-settings-helper-tab",
input_button: "entity-settings-helper-tab",
};

View File

@ -24,6 +24,11 @@ import {
fetchInputBoolean,
updateInputBoolean,
} from "../../../../../data/input_boolean";
import {
deleteInputButton,
fetchInputButton,
updateInputButton,
} from "../../../../../data/input_button";
import {
deleteInputDateTime,
fetchInputDateTime,
@ -55,6 +60,7 @@ import type { HomeAssistant } from "../../../../../types";
import type { Helper } from "../../../helpers/const";
import "../../../helpers/forms/ha-counter-form";
import "../../../helpers/forms/ha-input_boolean-form";
import "../../../helpers/forms/ha-input_button-form";
import "../../../helpers/forms/ha-input_datetime-form";
import "../../../helpers/forms/ha-input_number-form";
import "../../../helpers/forms/ha-input_select-form";
@ -69,6 +75,11 @@ const HELPERS = {
update: updateInputBoolean,
delete: deleteInputBoolean,
},
input_button: {
fetch: fetchInputButton,
update: updateInputButton,
delete: deleteInputButton,
},
input_text: {
fetch: fetchInputText,
update: updateInputText,

View File

@ -1,5 +1,6 @@
import { Counter } from "../../../data/counter";
import { InputBoolean } from "../../../data/input_boolean";
import { InputButton } from "../../../data/input_button";
import { InputDateTime } from "../../../data/input_datetime";
import { InputNumber } from "../../../data/input_number";
import { InputSelect } from "../../../data/input_select";
@ -8,6 +9,7 @@ import { Timer } from "../../../data/timer";
export const HELPER_DOMAINS = [
"input_boolean",
"input_button",
"input_text",
"input_number",
"input_datetime",
@ -18,6 +20,7 @@ export const HELPER_DOMAINS = [
export type Helper =
| InputBoolean
| InputButton
| InputText
| InputNumber
| InputSelect

View File

@ -10,6 +10,7 @@ import { domainIcon } from "../../../common/entity/domain_icon";
import "../../../components/ha-dialog";
import { createCounter } from "../../../data/counter";
import { createInputBoolean } from "../../../data/input_boolean";
import { createInputButton } from "../../../data/input_button";
import { createInputDateTime } from "../../../data/input_datetime";
import { createInputNumber } from "../../../data/input_number";
import { createInputSelect } from "../../../data/input_select";
@ -20,6 +21,7 @@ import { HomeAssistant } from "../../../types";
import { Helper } from "./const";
import "./forms/ha-counter-form";
import "./forms/ha-input_boolean-form";
import "./forms/ha-input_button-form";
import "./forms/ha-input_datetime-form";
import "./forms/ha-input_number-form";
import "./forms/ha-input_select-form";
@ -28,6 +30,7 @@ import "./forms/ha-timer-form";
const HELPERS = {
input_boolean: createInputBoolean,
input_button: createInputButton,
input_text: createInputText,
input_number: createInputNumber,
input_datetime: createInputDateTime,

View File

@ -0,0 +1,114 @@
import "@polymer/paper-input/paper-input";
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
import { customElement, property, state } from "lit/decorators";
import { fireEvent } from "../../../../common/dom/fire_event";
import "../../../../components/ha-icon-picker";
import { InputButton } from "../../../../data/input_button";
import { haStyle } from "../../../../resources/styles";
import { HomeAssistant } from "../../../../types";
@customElement("ha-input_button-form")
class HaInputButtonForm extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property() public new?: boolean;
@state() private _name!: string;
@state() private _icon!: string;
private _item?: InputButton;
set item(item: InputButton) {
this._item = item;
if (item) {
this._name = item.name || "";
this._icon = item.icon || "";
} else {
this._name = "";
this._icon = "";
}
}
public focus() {
this.updateComplete.then(() =>
(
this.shadowRoot?.querySelector("[dialogInitialFocus]") as HTMLElement
)?.focus()
);
}
protected render(): TemplateResult {
if (!this.hass) {
return html``;
}
const nameInvalid = !this._name || this._name.trim() === "";
return html`
<div class="form">
<paper-input
.value=${this._name}
.configValue=${"name"}
@value-changed=${this._valueChanged}
.label=${this.hass!.localize(
"ui.dialogs.helper_settings.generic.name"
)}
.errorMessage=${this.hass!.localize(
"ui.dialogs.helper_settings.required_error_msg"
)}
.invalid=${nameInvalid}
dialogInitialFocus
></paper-input>
<ha-icon-picker
.value=${this._icon}
.configValue=${"icon"}
@value-changed=${this._valueChanged}
.label=${this.hass!.localize(
"ui.dialogs.helper_settings.generic.icon"
)}
></ha-icon-picker>
</div>
`;
}
private _valueChanged(ev: CustomEvent) {
if (!this.new && !this._item) {
return;
}
ev.stopPropagation();
const configValue = (ev.target as any).configValue;
const value = ev.detail.value;
if (this[`_${configValue}`] === value) {
return;
}
const newValue = { ...this._item };
if (!value) {
delete newValue[configValue];
} else {
newValue[configValue] = ev.detail.value;
}
fireEvent(this, "value-changed", {
value: newValue,
});
}
static get styles(): CSSResultGroup {
return [
haStyle,
css`
.form {
color: var(--primary-text-color);
}
.row {
padding: 16px 0;
}
`,
];
}
}
declare global {
interface HTMLElementTagNameMap {
"ha-input_button-form": HaInputButtonForm;
}
}

View File

@ -28,6 +28,8 @@ const LAZY_LOAD_TYPES = {
"climate-entity": () => import("../entity-rows/hui-climate-entity-row"),
"cover-entity": () => import("../entity-rows/hui-cover-entity-row"),
"group-entity": () => import("../entity-rows/hui-group-entity-row"),
"input-button-entity": () =>
import("../entity-rows/hui-input-button-entity-row"),
"humidifier-entity": () => import("../entity-rows/hui-humidifier-entity-row"),
"input-datetime-entity": () =>
import("../entity-rows/hui-input-datetime-entity-row"),
@ -61,6 +63,7 @@ const DOMAIN_TO_ELEMENT_TYPE = {
group: "group",
humidifier: "humidifier",
input_boolean: "toggle",
input_button: "input-button",
input_number: "input-number",
input_select: "input-select",
input_text: "input-text",

View File

@ -0,0 +1,82 @@
import "@material/mwc-button/mwc-button";
import {
css,
CSSResultGroup,
html,
LitElement,
PropertyValues,
TemplateResult,
} from "lit";
import { customElement, property, state } from "lit/decorators";
import { UNAVAILABLE } from "../../../data/entity";
import { HomeAssistant } from "../../../types";
import { hasConfigOrEntityChanged } from "../common/has-changed";
import "../components/hui-generic-entity-row";
import { createEntityNotFoundWarning } from "../components/hui-warning";
import { ActionRowConfig, LovelaceRow } from "./types";
@customElement("hui-input-button-entity-row")
class HuiInputButtonEntityRow extends LitElement implements LovelaceRow {
@property({ attribute: false }) public hass!: HomeAssistant;
@state() private _config?: ActionRowConfig;
public setConfig(config: ActionRowConfig): void {
if (!config) {
throw new Error("Invalid configuration");
}
this._config = config;
}
protected shouldUpdate(changedProps: PropertyValues): boolean {
return hasConfigOrEntityChanged(this, changedProps);
}
protected render(): TemplateResult {
if (!this._config || !this.hass) {
return html``;
}
const stateObj = this.hass.states[this._config.entity];
if (!stateObj) {
return html`
<hui-warning>
${createEntityNotFoundWarning(this.hass, this._config.entity)}
</hui-warning>
`;
}
return html`
<hui-generic-entity-row .hass=${this.hass} .config=${this._config}>
<mwc-button
@click=${this._pressButton}
.disabled=${stateObj.state === UNAVAILABLE}
>
${this.hass.localize("ui.card.button.press")}
</mwc-button>
</hui-generic-entity-row>
`;
}
static get styles(): CSSResultGroup {
return css`
mwc-button:last-child {
margin-right: -0.57em;
}
`;
}
private _pressButton(ev): void {
ev.stopPropagation();
this.hass.callService("input_button", "press", {
entity_id: this._config!.entity,
});
}
}
declare global {
interface HTMLElementTagNameMap {
"hui-input-button-entity-row": HuiInputButtonEntityRow;
}
}

View File

@ -7,6 +7,7 @@ import "./state-card-climate";
import "./state-card-configurator";
import "./state-card-cover";
import "./state-card-display";
import "./state-card-input_button";
import "./state-card-input_number";
import "./state-card-input_select";
import "./state-card-input_text";

View File

@ -0,0 +1,54 @@
import "@material/mwc-button";
import { HassEntity } from "home-assistant-js-websocket";
import { CSSResultGroup, html, LitElement } from "lit";
import { customElement, property } from "lit/decorators";
import "../components/entity/ha-entity-toggle";
import "../components/entity/state-info";
import { UNAVAILABLE } from "../data/entity";
import { haStyle } from "../resources/styles";
import { HomeAssistant } from "../types";
@customElement("state-card-input_button")
export class StateCardInputButton extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property() public stateObj!: HassEntity;
@property({ type: Boolean }) public inDialog = false;
protected render() {
const stateObj = this.stateObj;
return html`
<div class="horizontal justified layout">
<state-info
.hass=${this.hass}
.stateObj=${stateObj}
.inDialog=${this.inDialog}
></state-info>
<mwc-button
@click=${this._pressButton}
.disabled=${stateObj.state === UNAVAILABLE}
>
${this.hass.localize("ui.card.button.press")}
</mwc-button>
</div>
`;
}
private _pressButton(ev: Event) {
ev.stopPropagation();
this.hass.callService("input_button", "press", {
entity_id: this.stateObj.entity_id,
});
}
static get styles(): CSSResultGroup {
return haStyle;
}
}
declare global {
interface HTMLElementTagNameMap {
"state-card-input_button": StateCardInputButton;
}
}

View File

@ -1242,6 +1242,7 @@
"input_number": "Number",
"input_select": "Dropdown",
"input_boolean": "Toggle",
"input_button": "Button",
"input_datetime": "Date and/or time",
"counter": "Counter",
"timer": "Timer"
@ -1441,6 +1442,7 @@
"person": "People",
"zone": "Zones",
"input_boolean": "Input booleans",
"input_button": "Input buttons",
"input_text": "Input texts",
"input_number": "Input numbers",
"input_datetime": "Input date times",