Add support for input_button / Button Helper (#10974)
Co-authored-by: Zack Barett <arnett.zackary@gmail.com>
This commit is contained in:
parent
3bbe1603eb
commit
f852208eff
|
@ -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",
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
});
|
|
@ -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",
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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",
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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";
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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",
|
||||
|
|
Loading…
Reference in New Issue