Convert automation conditions to Lit (#4321)

* Convert automation conditions to Lit

* Split condition editor and row

* Comments

* Update automation.ts

* Update automation.ts
This commit is contained in:
Bram Kragten 2019-12-05 19:48:06 +01:00 committed by GitHub
parent e6ac0258e3
commit 073428849e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
42 changed files with 1193 additions and 992 deletions

View File

@ -4,6 +4,7 @@ import {
} from "home-assistant-js-websocket";
import { HomeAssistant } from "../types";
import { navigate } from "../common/navigate";
import { DeviceCondition, DeviceTrigger } from "./device_automation";
export interface AutomationEntity extends HassEntityBase {
attributes: HassEntityAttributeBase & {
@ -15,11 +16,162 @@ export interface AutomationEntity extends HassEntityBase {
export interface AutomationConfig {
alias: string;
description: string;
trigger: any[];
condition?: any[];
trigger: Trigger[];
condition?: Condition[];
action: any[];
}
export interface ForDict {
hours?: number | string;
minutes?: number | string;
seconds?: number | string;
}
export interface StateTrigger {
platform: "state";
entity_id?: string;
from?: string | number;
to?: string | number;
for?: string | number | ForDict;
}
export interface MqttTrigger {
platform: "mqtt";
topic: string;
payload?: string;
}
export interface GeoLocationTrigger {
platform: "geo_location";
source: "string";
zone: "string";
event: "enter" | "leave";
}
export interface HassTrigger {
platform: "homeassistant";
event: "start" | "shutdown";
}
export interface NumericStateTrigger {
platform: "numeric_state";
entity_id: string;
above?: number;
below?: number;
value_template?: string;
for?: string | number | ForDict;
}
export interface SunTrigger {
platform: "sun";
offset: number;
event: "sunrise" | "sunset";
}
export interface TimePatternTrigger {
platform: "time_pattern";
hours?: number | string;
minutes?: number | string;
seconds?: number | string;
}
export interface WebhookTrigger {
platform: "webhook";
webhook_id: string;
}
export interface ZoneTrigger {
platform: "zone";
entity_id: string;
zone: string;
event: "enter" | "leave";
}
export interface TimeTrigger {
platform: "time";
at: string;
}
export interface TemplateTrigger {
platform: "template";
value_template: string;
}
export interface EventTrigger {
platform: "event";
event_type: string;
event_data: any;
}
export type Trigger =
| StateTrigger
| MqttTrigger
| GeoLocationTrigger
| HassTrigger
| NumericStateTrigger
| SunTrigger
| TimePatternTrigger
| WebhookTrigger
| ZoneTrigger
| TimeTrigger
| TemplateTrigger
| EventTrigger
| DeviceTrigger;
export interface LogicalCondition {
condition: "and" | "or";
conditions: Condition[];
}
export interface StateCondition {
condition: "state";
entity_id: string;
state: string | number;
}
export interface NumericStateCondition {
condition: "numeric_state";
entity_id: string;
above?: number;
below?: number;
value_template?: string;
}
export interface SunCondition {
condition: "sun";
after_offset: number;
before_offset: number;
after: "sunrise" | "sunset";
before: "sunrise" | "sunset";
}
export interface ZoneCondition {
condition: "zone";
entity_id: string;
zone: string;
}
export interface TimeCondition {
condition: "time";
after: string;
before: string;
}
export interface TemplateCondition {
condition: "template";
value_template: string;
}
export type Condition =
| StateCondition
| NumericStateCondition
| SunCondition
| ZoneCondition
| TimeCondition
| TemplateCondition
| DeviceCondition
| LogicalCondition;
export const deleteAutomation = (hass: HomeAssistant, id: string) =>
hass.callApi("DELETE", `config/automation/config/${id}`);

View File

@ -0,0 +1,128 @@
import "@polymer/paper-item/paper-item";
import "@polymer/paper-listbox/paper-listbox";
// tslint:disable-next-line
import { PaperListboxElement } from "@polymer/paper-listbox/paper-listbox";
import { customElement, html, LitElement, property } from "lit-element";
import { dynamicElement } from "../../../../common/dom/dynamic-element-directive";
import { fireEvent } from "../../../../common/dom/fire_event";
import "../../../../components/ha-card";
import { HomeAssistant } from "../../../../types";
import "./types/ha-automation-condition-device";
import "./types/ha-automation-condition-state";
import "./types/ha-automation-condition-numeric_state";
import "./types/ha-automation-condition-sun";
import "./types/ha-automation-condition-template";
import "./types/ha-automation-condition-time";
import "./types/ha-automation-condition-zone";
import "./types/ha-automation-condition-and";
import "./types/ha-automation-condition-or";
import { Condition } from "../../../../data/automation";
const OPTIONS = [
"device",
"and",
"or",
"state",
"numeric_state",
"sun",
"template",
"time",
"zone",
];
@customElement("ha-automation-condition-editor")
export default class HaAutomationConditionEditor extends LitElement {
@property() public hass!: HomeAssistant;
@property() public condition!: Condition;
@property() public yamlMode = false;
protected render() {
if (!this.condition) {
return html``;
}
const selected = OPTIONS.indexOf(this.condition.condition);
const yamlMode = this.yamlMode || selected === -1;
return html`
${yamlMode
? html`
<div style="margin-right: 24px;">
${selected === -1
? html`
${this.hass.localize(
"ui.panel.config.automation.editor.conditions.unsupported_condition",
"condition",
this.condition.condition
)}
`
: ""}
<ha-yaml-editor
.value=${this.condition}
@value-changed=${this._onYamlChange}
></ha-yaml-editor>
</div>
`
: html`
<paper-dropdown-menu-light
.label=${this.hass.localize(
"ui.panel.config.automation.editor.conditions.type_select"
)}
no-animations
>
<paper-listbox
slot="dropdown-content"
.selected=${selected}
@iron-select=${this._typeChanged}
>
${OPTIONS.map(
(opt) => html`
<paper-item .condition=${opt}>
${this.hass.localize(
`ui.panel.config.automation.editor.conditions.type.${opt}.label`
)}
</paper-item>
`
)}
</paper-listbox>
</paper-dropdown-menu-light>
<div>
${dynamicElement(
`ha-automation-condition-${this.condition.condition}`,
{ hass: this.hass, condition: this.condition }
)}
</div>
`}
`;
}
private _typeChanged(ev: CustomEvent) {
const type = ((ev.target as PaperListboxElement)?.selectedItem as any)
?.condition;
if (!type) {
return;
}
const elClass = customElements.get(`ha-automation-condition-${type}`);
if (type !== this.condition.condition) {
fireEvent(this, "value-changed", {
value: {
condition: type,
...elClass.defaultConfig,
},
});
}
}
private _onYamlChange(ev: CustomEvent) {
ev.stopPropagation();
fireEvent(this, "value-changed", { value: ev.detail.value });
}
}
declare global {
interface HTMLElementTagNameMap {
"ha-automation-condition-editor": HaAutomationConditionEditor;
}
}

View File

@ -0,0 +1,146 @@
import "@polymer/paper-icon-button/paper-icon-button";
import "@polymer/paper-item/paper-item";
import "@polymer/paper-menu-button/paper-menu-button";
import {
css,
CSSResult,
customElement,
html,
LitElement,
property,
} from "lit-element";
import { fireEvent } from "../../../../common/dom/fire_event";
import "../../../../components/ha-card";
import { HomeAssistant } from "../../../../types";
import "./ha-automation-condition-editor";
import { Condition } from "../../../../data/automation";
export interface ConditionElement extends LitElement {
condition: Condition;
}
export const handleChangeEvent = (
element: ConditionElement,
ev: CustomEvent
) => {
ev.stopPropagation();
const name = (ev.target as any)?.name;
if (!name) {
return;
}
const newVal = ev.detail.value;
if ((element.condition[name] || "") === newVal) {
return;
}
let newCondition: Condition;
if (!newVal) {
newCondition = { ...element.condition };
delete newCondition[name];
} else {
newCondition = { ...element.condition, [name]: newVal };
}
fireEvent(element, "value-changed", { value: newCondition });
};
@customElement("ha-automation-condition-row")
export default class HaAutomationConditionRow extends LitElement {
@property() public hass!: HomeAssistant;
@property() public condition!: Condition;
@property() private _yamlMode = false;
protected render() {
if (!this.condition) {
return html``;
}
return html`
<ha-card>
<div class="card-content">
<div class="card-menu">
<paper-menu-button
no-animations
horizontal-align="right"
horizontal-offset="-5"
vertical-offset="-5"
close-on-activate
>
<paper-icon-button
icon="hass:dots-vertical"
slot="dropdown-trigger"
></paper-icon-button>
<paper-listbox slot="dropdown-content">
<paper-item @click=${this._switchYamlMode}>
${this._yamlMode
? this.hass.localize(
"ui.panel.config.automation.editor.edit_ui"
)
: this.hass.localize(
"ui.panel.config.automation.editor.edit_yaml"
)}
</paper-item>
<paper-item disabled>
${this.hass.localize(
"ui.panel.config.automation.editor.conditions.duplicate"
)}
</paper-item>
<paper-item @click=${this._onDelete}>
${this.hass.localize(
"ui.panel.config.automation.editor.conditions.delete"
)}
</paper-item>
</paper-listbox>
</paper-menu-button>
</div>
<ha-automation-condition-editor
.yamlMode=${this._yamlMode}
.hass=${this.hass}
.condition=${this.condition}
></ha-automation-condition-editor>
</div>
</ha-card>
`;
}
private _onDelete() {
if (
confirm(
this.hass.localize(
"ui.panel.config.automation.editor.conditions.delete_confirm"
)
)
) {
fireEvent(this, "value-changed", { value: null });
}
}
private _switchYamlMode() {
this._yamlMode = !this._yamlMode;
}
static get styles(): CSSResult {
return css`
.card-menu {
position: absolute;
top: 0;
right: 0;
z-index: 3;
color: var(--primary-text-color);
}
.rtl .card-menu {
right: auto;
left: 0;
}
.card-menu paper-item {
cursor: pointer;
}
`;
}
}
declare global {
interface HTMLElementTagNameMap {
"ha-automation-condition-row": HaAutomationConditionRow;
}
}

View File

@ -0,0 +1,92 @@
import {
LitElement,
customElement,
html,
property,
CSSResult,
css,
} from "lit-element";
import "@material/mwc-button";
import "../../../../components/ha-card";
import { HaStateCondition } from "./types/ha-automation-condition-state";
import { fireEvent } from "../../../../common/dom/fire_event";
import { HomeAssistant } from "../../../../types";
import "./ha-automation-condition-row";
import { Condition } from "../../../../data/automation";
@customElement("ha-automation-condition")
export default class HaAutomationCondition extends LitElement {
@property() public hass!: HomeAssistant;
@property() public conditions!: Condition[];
protected render() {
return html`
${this.conditions.map(
(cond, idx) => html`
<ha-automation-condition-row
.index=${idx}
.condition=${cond}
@value-changed=${this._conditionChanged}
.hass=${this.hass}
></ha-automation-condition-row>
`
)}
<ha-card>
<div class="card-actions add-card">
<mwc-button @click=${this._addCondition}>
${this.hass.localize(
"ui.panel.config.automation.editor.conditions.add"
)}
</mwc-button>
</div>
</ha-card>
`;
}
private _addCondition() {
const conditions = this.conditions.concat({
condition: "state",
...HaStateCondition.defaultConfig,
});
fireEvent(this, "value-changed", { value: conditions });
}
private _conditionChanged(ev: CustomEvent) {
ev.stopPropagation();
const conditions = [...this.conditions];
const newValue = ev.detail.value;
const index = (ev.target as any).index;
if (newValue === null) {
conditions.splice(index, 1);
} else {
conditions[index] = newValue;
}
fireEvent(this, "value-changed", { value: conditions });
}
static get styles(): CSSResult {
return css`
ha-automation-condition-row,
ha-card {
display: block;
margin-top: 16px;
}
.add-card mwc-button {
display: block;
text-align: center;
}
`;
}
}
declare global {
interface HTMLElementTagNameMap {
"ha-automation-condition": HaAutomationCondition;
}
}

View File

@ -0,0 +1,11 @@
import { HaLogicalCondition } from "./ha-automation-condition-logical";
import { customElement } from "lit-element";
@customElement("ha-automation-condition-and")
export class HaAndCondition extends HaLogicalCondition {}
declare global {
interface HTMLElementTagNameMap {
"ha-automation-condition-and": HaAndCondition;
}
}

View File

@ -0,0 +1,131 @@
import "../../../../../components/device/ha-device-picker";
import "../../../../../components/device/ha-device-condition-picker";
import "../../../../../components/ha-form/ha-form";
import {
fetchDeviceConditionCapabilities,
deviceAutomationsEqual,
DeviceCondition,
} from "../../../../../data/device_automation";
import { LitElement, customElement, property, html } from "lit-element";
import { fireEvent } from "../../../../../common/dom/fire_event";
import { HomeAssistant } from "../../../../../types";
@customElement("ha-automation-condition-device")
export class HaDeviceCondition extends LitElement {
@property() public hass!: HomeAssistant;
@property() public condition!: DeviceCondition;
@property() private _deviceId?: string;
@property() private _capabilities?;
private _origCondition?: DeviceCondition;
public static get defaultConfig() {
return {
device_id: "",
domain: "",
entity_id: "",
};
}
protected render() {
if (this._deviceId === undefined) {
this._deviceId = this.condition.device_id;
}
const extraFieldsData =
this._capabilities && this._capabilities.extra_fields
? this._capabilities.extra_fields.map((item) => {
return { [item.name]: this.condition[item.name] };
})
: undefined;
return html`
<ha-device-picker
.value=${this._deviceId}
@value-changed=${this._devicePicked}
.hass=${this.hass}
label="Device"
></ha-device-picker>
<ha-device-condition-picker
.value=${this.condition}
.deviceId=${this._deviceId}
@value-changed=${this._deviceConditionPicked}
.hass=${this.hass}
label="Condition"
></ha-device-condition-picker>
${extraFieldsData
? html`
<ha-form
.data=${Object.assign({}, ...extraFieldsData)}
.schema=${this._capabilities.extra_fields}
.computeLabel=${this._extraFieldsComputeLabelCallback(
this.hass.localize
)}
@value-changed=${this._extraFieldsChanged}
></ha-form>
`
: ""}
`;
}
protected firstUpdated() {
if (!this._capabilities) {
this._getCapabilities();
}
if (this.condition) {
this._origCondition = this.condition;
}
}
protected updated(changedPros) {
const prevCondition = changedPros.get("condition");
if (
prevCondition &&
!deviceAutomationsEqual(prevCondition, this.condition)
) {
this._getCapabilities();
}
}
private async _getCapabilities() {
const condition = this.condition;
this._capabilities = condition.domain
? await fetchDeviceConditionCapabilities(this.hass, condition)
: null;
}
private _devicePicked(ev) {
ev.stopPropagation();
this._deviceId = ev.target.value;
}
private _deviceConditionPicked(ev) {
ev.stopPropagation();
let condition = ev.detail.value;
if (
this._origCondition &&
deviceAutomationsEqual(this._origCondition, condition)
) {
condition = this._origCondition;
}
fireEvent(this, "value-changed", { value: condition });
}
private _extraFieldsChanged(ev) {
ev.stopPropagation();
fireEvent(this, "value-changed", {
value: {
...this.condition,
...ev.detail.value,
},
});
}
private _extraFieldsComputeLabelCallback(localize) {
// Returns a callback for ha-form to calculate labels per schema object
return (schema) =>
localize(
`ui.panel.config.automation.editor.conditions.type.device.extra_fields.${schema.name}`
) || schema.name;
}
}

View File

@ -0,0 +1,39 @@
import { customElement, html, LitElement, property } from "lit-element";
import { fireEvent } from "../../../../../common/dom/fire_event";
import { HomeAssistant } from "../../../../../types";
import { ConditionElement } from "../ha-automation-condition-row";
import "../ha-automation-condition";
import { LogicalCondition } from "../../../../../data/automation";
@customElement("ha-automation-condition-logical")
export class HaLogicalCondition extends LitElement implements ConditionElement {
@property() public hass!: HomeAssistant;
@property() public condition!: LogicalCondition;
public static get defaultConfig() {
return { conditions: [{ condition: "state" }] };
}
protected render() {
return html`
<ha-automation-condition
.conditions=${this.condition.conditions || []}
@value-changed=${this._valueChanged}
.hass=${this.hass}
></ha-automation-condition>
`;
}
private _valueChanged(ev: CustomEvent): void {
ev.stopPropagation();
fireEvent(this, "value-changed", {
value: { ...this.condition, conditions: ev.detail.value },
});
}
}
declare global {
interface HTMLElementTagNameMap {
"ha-automation-condition-logical": HaLogicalCondition;
}
}

View File

@ -0,0 +1,76 @@
import "@polymer/paper-input/paper-input";
import "../../../../../components/ha-textarea";
import "../../../../../components/entity/ha-entity-picker";
import { LitElement, html, customElement, property } from "lit-element";
import { HomeAssistant } from "../../../../../types";
import { fireEvent } from "../../../../../common/dom/fire_event";
import { handleChangeEvent } from "../ha-automation-condition-row";
import { NumericStateCondition } from "../../../../../data/automation";
@customElement("ha-automation-condition-numeric_state")
export default class HaNumericStateCondition extends LitElement {
@property() public hass!: HomeAssistant;
@property() public condition!: NumericStateCondition;
public static get defaultConfig() {
return {
entity_id: "",
};
}
public render() {
const { value_template, entity_id, below, above } = this.condition;
return html`
<ha-entity-picker
.value="${entity_id}"
@value-changed="${this._entityPicked}"
.hass="${this.hass}"
allow-custom-entity
></ha-entity-picker>
<paper-input
.label=${this.hass.localize(
"ui.panel.config.automation.editor.conditions.type.numeric_state.above"
)}
name="above"
.value=${above}
@value-changed=${this._valueChanged}
></paper-input>
<paper-input
.label=${this.hass.localize(
"ui.panel.config.automation.editor.conditions.type.numeric_state.below"
)}
name="below"
.value=${below}
@value-changed=${this._valueChanged}
></paper-input>
<ha-textarea
.label=${this.hass.localize(
"ui.panel.config.automation.editor.conditions.type.numeric_state.value_template"
)}
name="value_template"
.value=${value_template}
@value-changed=${this._valueChanged}
dir="ltr"
></ha-textarea>
`;
}
private _valueChanged(ev: CustomEvent): void {
handleChangeEvent(this, ev);
}
private _entityPicked(ev) {
ev.stopPropagation();
fireEvent(this, "value-changed", {
value: { ...this.condition, entity_id: ev.detail.value },
});
}
}
declare global {
interface HTMLElementTagNameMap {
"ha-automation-condition-numeric_state": HaNumericStateCondition;
}
}

View File

@ -0,0 +1,11 @@
import { HaLogicalCondition } from "./ha-automation-condition-logical";
import { customElement } from "lit-element";
@customElement("ha-automation-condition-or")
export class HaOrCondition extends HaLogicalCondition {}
declare global {
interface HTMLElementTagNameMap {
"ha-automation-condition-or": HaOrCondition;
}
}

View File

@ -0,0 +1,59 @@
import "@polymer/paper-input/paper-input";
import { customElement, html, LitElement, property } from "lit-element";
import { fireEvent } from "../../../../../common/dom/fire_event";
import "../../../../../components/entity/ha-entity-picker";
import { HomeAssistant } from "../../../../../types";
import {
handleChangeEvent,
ConditionElement,
} from "../ha-automation-condition-row";
import { PolymerChangedEvent } from "../../../../../polymer-types";
import { StateCondition } from "../../../../../data/automation";
@customElement("ha-automation-condition-state")
export class HaStateCondition extends LitElement implements ConditionElement {
@property() public hass!: HomeAssistant;
@property() public condition!: StateCondition;
public static get defaultConfig() {
return { entity_id: "", state: "" };
}
protected render() {
const { entity_id, state } = this.condition;
return html`
<ha-entity-picker
.value=${entity_id}
@value-changed=${this._entityPicked}
.hass=${this.hass}
allow-custom-entity
></ha-entity-picker>
<paper-input
.label=${this.hass.localize(
"ui.panel.config.automation.editor.conditions.type.state.state"
)}
.name=${"state"}
.value=${state}
@value-changed=${this._valueChanged}
></paper-input>
`;
}
private _valueChanged(ev: CustomEvent): void {
handleChangeEvent(this, ev);
}
private _entityPicked(ev: PolymerChangedEvent<string>) {
ev.stopPropagation();
fireEvent(this, "value-changed", {
value: { ...this.condition, entity_id: ev.detail.value },
});
}
}
declare global {
interface HTMLElementTagNameMap {
"ha-automation-condition-state": HaStateCondition;
}
}

View File

@ -0,0 +1,107 @@
import "@polymer/paper-input/paper-input";
import "@polymer/paper-radio-button/paper-radio-button";
import "@polymer/paper-radio-group/paper-radio-group";
// tslint:disable-next-line
import { PaperRadioGroupElement } from "@polymer/paper-radio-group/paper-radio-group";
import { LitElement, customElement, property, html } from "lit-element";
import { HomeAssistant } from "../../../../../types";
import {
handleChangeEvent,
ConditionElement,
} from "../ha-automation-condition-row";
import { fireEvent } from "../../../../../common/dom/fire_event";
import { SunCondition } from "../../../../../data/automation";
@customElement("ha-automation-condition-sun")
export class HaSunCondition extends LitElement implements ConditionElement {
@property() public hass!: HomeAssistant;
@property() public condition!: SunCondition;
public static get defaultConfig() {
return {};
}
protected render() {
const { after, after_offset, before, before_offset } = this.condition;
return html`
<label id="beforelabel">
${this.hass.localize(
"ui.panel.config.automation.editor.conditions.type.sun.before"
)}
</label>
<paper-radio-group
.selected=${before}
.name=${"before"}
aria-labelledby="beforelabel"
@paper-radio-group-changed=${this._radioGroupPicked}
>
<paper-radio-button name="sunrise">
${this.hass.localize(
"ui.panel.config.automation.editor.conditions.type.sun.sunrise"
)}
</paper-radio-button>
<paper-radio-button name="sunset">
${this.hass.localize(
"ui.panel.config.automation.editor.conditions.type.sun.sunset"
)}
</paper-radio-button>
</paper-radio-group>
<paper-input
.label=${this.hass.localize(
"ui.panel.config.automation.editor.conditions.type.sun.before_offset"
)}
name="before_offset"
.value=${before_offset}
@value-changed=${this._valueChanged}
></paper-input>
<label id="afterlabel">
${this.hass.localize(
"ui.panel.config.automation.editor.conditions.type.sun.after"
)}
</label>
<paper-radio-group
.selected=${after}
.name=${"after"}
aria-labelledby="afterlabel"
@paper-radio-group-changed=${this._radioGroupPicked}
>
<paper-radio-button name="sunrise">
${this.hass.localize(
"ui.panel.config.automation.editor.conditions.type.sun.sunrise"
)}
</paper-radio-button>
<paper-radio-button name="sunset">
${this.hass.localize(
"ui.panel.config.automation.editor.conditions.type.sun.sunset"
)}
</paper-radio-button>
</paper-radio-group>
<paper-input
.label=${this.hass.localize(
"ui.panel.config.automation.editor.conditions.type.sun.after_offset"
)}
name="after_offset"
.value=${after_offset}
@value-changed=${this._valueChanged}
></paper-input>
`;
}
private _valueChanged(ev: CustomEvent): void {
handleChangeEvent(this, ev);
}
private _radioGroupPicked(ev) {
const key = ev.target.name;
ev.stopPropagation();
fireEvent(this, "value-changed", {
value: {
...this.condition,
[key]: (ev.target as PaperRadioGroupElement).selected,
},
});
}
}

View File

@ -0,0 +1,34 @@
import "../../../../../components/ha-textarea";
import { LitElement, property, html, customElement } from "lit-element";
import { HomeAssistant } from "../../../../../types";
import { handleChangeEvent } from "../ha-automation-condition-row";
import { TemplateCondition } from "../../../../../data/automation";
@customElement("ha-automation-condition-template")
export class HaTemplateCondition extends LitElement {
@property() public hass!: HomeAssistant;
@property() public condition!: TemplateCondition;
public static get defaultConfig() {
return { value_template: "" };
}
protected render() {
const { value_template } = this.condition;
return html`
<ha-textarea
.label=${this.hass.localize(
"ui.panel.config.automation.editor.conditions.type.template.value_template"
)}
name="value_template"
.value=${value_template}
@value-changed=${this._valueChanged}
dir="ltr"
></ha-textarea>
`;
}
private _valueChanged(ev: CustomEvent): void {
handleChangeEvent(this, ev);
}
}

View File

@ -0,0 +1,44 @@
import "@polymer/paper-input/paper-input";
import { LitElement, html, property, customElement } from "lit-element";
import { HomeAssistant } from "../../../../../types";
import {
handleChangeEvent,
ConditionElement,
} from "../ha-automation-condition-row";
import { TimeCondition } from "../../../../../data/automation";
@customElement("ha-automation-condition-time")
export class HaTimeCondition extends LitElement implements ConditionElement {
@property() public hass!: HomeAssistant;
@property() public condition!: TimeCondition;
public static get defaultConfig() {
return {};
}
protected render() {
const { after, before } = this.condition;
return html`
<paper-input
.label=${this.hass.localize(
"ui.panel.config.automation.editor.conditions.type.time.after"
)}
name="after"
.value=${after}
@value-changed=${this._valueChanged}
></paper-input>
<paper-input
.label=${this.hass.localize(
"ui.panel.config.automation.editor.conditions.type.time.before"
)}
name="before"
.value=${before}
@value-changed=${this._valueChanged}
></paper-input>
`;
}
private _valueChanged(ev: CustomEvent): void {
handleChangeEvent(this, ev);
}
}

View File

@ -0,0 +1,78 @@
import "@polymer/paper-radio-button/paper-radio-button";
import "../../../../../components/entity/ha-entity-picker";
import { hasLocation } from "../../../../../common/entity/has_location";
import { computeStateDomain } from "../../../../../common/entity/compute_state_domain";
import { LitElement, property, html, customElement } from "lit-element";
import { HomeAssistant } from "../../../../../types";
import { PolymerChangedEvent } from "../../../../../polymer-types";
import { fireEvent } from "../../../../../common/dom/fire_event";
import { ZoneCondition } from "../../../../../data/automation";
function zoneAndLocationFilter(stateObj) {
return hasLocation(stateObj) && computeStateDomain(stateObj) !== "zone";
}
@customElement("ha-automation-condition-zone")
export class HaZoneCondition extends LitElement {
@property() public hass!: HomeAssistant;
@property() public condition!: ZoneCondition;
public static get defaultConfig() {
return {
entity_id: "",
zone: "",
};
}
protected render() {
const { entity_id, zone } = this.condition;
return html`
<ha-entity-picker
.label=${this.hass.localize(
"ui.panel.config.automation.editor.conditions.type.zone.entity"
)}
.value=${entity_id}
@value-changed=${this._entityPicked}
.hass=${this.hass}
allow-custom-entity
.entityFilter=${zoneAndLocationFilter}
></ha-entity-picker>
<ha-entity-picker
.label=${this.hass.localize(
"ui.panel.config.automation.editor.conditions.type.zone.zone"
)}
.value=${zone}
@value-changed=${this._zonePicked}
.hass=${this.hass}
allow-custom-entity
.includeDomains=${["zone"]}
></ha-entity-picker>
<label id="eventlabel">
${this.hass.localize(
"ui.panel.config.automation.editor.conditions.type.zone.event"
)}
</label>
`;
}
private _entityPicked(ev: PolymerChangedEvent<string>) {
ev.stopPropagation();
fireEvent(this, "value-changed", {
value: { ...this.condition, entity_id: ev.detail.value },
});
}
private _zonePicked(ev: PolymerChangedEvent<string>) {
ev.stopPropagation();
fireEvent(this, "value-changed", {
value: { ...this.condition, zone: ev.detail.value },
});
}
}
declare global {
interface HTMLElementTagNameMap {
"ha-automation-condition-zone": HaZoneCondition;
}
}

View File

@ -30,7 +30,8 @@ import "./types/ha-automation-trigger-time";
import "./types/ha-automation-trigger-time_pattern";
import "./types/ha-automation-trigger-webhook";
import "./types/ha-automation-trigger-zone";
import { DeviceTrigger } from "../../../../data/device_automation";
import { Trigger } from "../../../../data/automation";
const OPTIONS = [
"device",
@ -48,103 +49,6 @@ const OPTIONS = [
"zone",
];
export interface ForDict {
hours?: number | string;
minutes?: number | string;
seconds?: number | string;
}
export interface StateTrigger {
platform: "state";
entity_id: string;
from?: string | number;
to?: string | number;
for?: string | number | ForDict;
}
export interface MqttTrigger {
platform: "mqtt";
topic: string;
payload?: string;
}
export interface GeoLocationTrigger {
platform: "geo_location";
source: "string";
zone: "string";
event: "enter" | "leave";
}
export interface HassTrigger {
platform: "homeassistant";
event: "start" | "shutdown";
}
export interface NumericStateTrigger {
platform: "numeric_state";
entity_id: string;
above?: number;
below?: number;
value_template?: string;
for?: string | number | ForDict;
}
export interface SunTrigger {
platform: "sun";
offset: number;
event: "sunrise" | "sunset";
}
export interface TimePatternTrigger {
platform: "time_pattern";
hours?: number | string;
minutes?: number | string;
seconds?: number | string;
}
export interface WebhookTrigger {
platform: "webhook";
webhook_id: string;
}
export interface ZoneTrigger {
platform: "zone";
entity_id: string;
zone: string;
event: "enter" | "leave";
}
export interface TimeTrigger {
platform: "time";
at: string;
}
export interface TemplateTrigger {
platform: "template";
value_template: string;
}
export interface EventTrigger {
platform: "event";
event_type: string;
event_data: any;
}
export type Trigger =
| StateTrigger
| MqttTrigger
| GeoLocationTrigger
| HassTrigger
| NumericStateTrigger
| SunTrigger
| TimePatternTrigger
| WebhookTrigger
| ZoneTrigger
| TimeTrigger
| TemplateTrigger
| EventTrigger
| DeviceTrigger;
export interface TriggerElement extends LitElement {
trigger: Trigger;
}
@ -181,11 +85,9 @@ export default class HaAutomationTriggerRow extends LitElement {
if (!this.trigger) {
return html``;
}
const hasEditor = OPTIONS.includes(this.trigger.platform);
if (!hasEditor) {
this._yamlMode = true;
}
const selected = OPTIONS.indexOf(this.trigger.platform);
const yamlMode = this._yamlMode || selected === -1;
return html`
<ha-card>
<div class="card-content">
@ -202,8 +104,11 @@ export default class HaAutomationTriggerRow extends LitElement {
slot="dropdown-trigger"
></paper-icon-button>
<paper-listbox slot="dropdown-content">
<paper-item @click=${this._switchYamlMode}>
${this._yamlMode
<paper-item
@click=${this._switchYamlMode}
.disabled=${selected === -1}
>
${yamlMode
? this.hass.localize(
"ui.panel.config.automation.editor.edit_ui"
)
@ -224,10 +129,10 @@ export default class HaAutomationTriggerRow extends LitElement {
</paper-listbox>
</paper-menu-button>
</div>
${this._yamlMode
${yamlMode
? html`
<div style="margin-right: 24px;">
${!hasEditor
${selected === -1
? html`
${this.hass.localize(
"ui.panel.config.automation.editor.triggers.unsupported_platform",

View File

@ -13,41 +13,42 @@ import { fireEvent } from "../../../../common/dom/fire_event";
import { HomeAssistant } from "../../../../types";
import "./ha-automation-trigger-row";
import { HaStateTrigger } from "./types/ha-automation-trigger-state";
import { Trigger } from "../../../../data/automation";
@customElement("ha-automation-trigger")
export default class HaAutomationTrigger extends LitElement {
@property() public hass!: HomeAssistant;
@property() public triggers;
@property() public triggers!: Trigger[];
protected render() {
return html`
<div class="triggers">
${this.triggers.map(
(trg, idx) => html`
<ha-automation-trigger-row
.index=${idx}
.trigger=${trg}
@value-changed=${this._triggerChanged}
.hass=${this.hass}
></ha-automation-trigger-row>
`
)}
<ha-card>
<div class="card-actions add-card">
<mwc-button @click=${this._addTrigger}>
${this.hass.localize(
"ui.panel.config.automation.editor.triggers.add"
)}
</mwc-button>
</div>
</ha-card>
</div>
${this.triggers.map(
(trg, idx) => html`
<ha-automation-trigger-row
.index=${idx}
.trigger=${trg}
@value-changed=${this._triggerChanged}
.hass=${this.hass}
></ha-automation-trigger-row>
`
)}
<ha-card>
<div class="card-actions add-card">
<mwc-button @click=${this._addTrigger}>
${this.hass.localize(
"ui.panel.config.automation.editor.triggers.add"
)}
</mwc-button>
</div>
</ha-card>
`;
}
private _addTrigger() {
const triggers = this.triggers.concat({
platform: "state",
...HaStateTrigger.defaultConfig,
});
fireEvent(this, "value-changed", { value: triggers });
@ -70,12 +71,9 @@ export default class HaAutomationTrigger extends LitElement {
static get styles(): CSSResult {
return css`
.triggers,
.script {
margin-top: -16px;
}
.triggers ha-card,
.script ha-card {
ha-automation-trigger-row,
ha-card {
display: block;
margin-top: 16px;
}
.add-card mwc-button {

View File

@ -4,11 +4,11 @@ import "../../../../../components/ha-yaml-editor";
import { LitElement, property, customElement } from "lit-element";
import {
TriggerElement,
EventTrigger,
handleChangeEvent,
} from "../ha-automation-trigger-row";
import { HomeAssistant } from "../../../../../types";
import { html } from "lit-html";
import { EventTrigger } from "../../../../../data/automation";
@customElement("ha-automation-trigger-event")
export class HaEventTrigger extends LitElement implements TriggerElement {

View File

@ -5,11 +5,9 @@ import { PaperRadioGroupElement } from "@polymer/paper-radio-group/paper-radio-g
import "../../../../../components/entity/ha-entity-picker";
import { LitElement, customElement, property, html } from "lit-element";
import { HomeAssistant } from "../../../../../types";
import {
GeoLocationTrigger,
handleChangeEvent,
} from "../ha-automation-trigger-row";
import { handleChangeEvent } from "../ha-automation-trigger-row";
import { fireEvent } from "../../../../../common/dom/fire_event";
import { GeoLocationTrigger } from "../../../../../data/automation";
@customElement("ha-automation-trigger-geo_location")
export default class HaGeolocationTrigger extends LitElement {

View File

@ -5,7 +5,7 @@ import { PaperRadioGroupElement } from "@polymer/paper-radio-group/paper-radio-g
import { LitElement, html, property, customElement } from "lit-element";
import { fireEvent } from "../../../../../common/dom/fire_event";
import { HomeAssistant } from "../../../../../types";
import { HassTrigger } from "../ha-automation-trigger-row";
import { HassTrigger } from "../../../../../data/automation";
@customElement("ha-automation-trigger-homeassistant")
export default class HaHassTrigger extends LitElement {

View File

@ -4,8 +4,8 @@ import { HomeAssistant } from "../../../../../types";
import {
handleChangeEvent,
TriggerElement,
MqttTrigger,
} from "../ha-automation-trigger-row";
import { MqttTrigger } from "../../../../../data/automation";
@customElement("ha-automation-trigger-mqtt")
export class HaMQTTTrigger extends LitElement implements TriggerElement {

View File

@ -5,11 +5,8 @@ import "../../../../../components/entity/ha-entity-picker";
import { LitElement, html, customElement, property } from "lit-element";
import { HomeAssistant } from "../../../../../types";
import { fireEvent } from "../../../../../common/dom/fire_event";
import {
NumericStateTrigger,
ForDict,
handleChangeEvent,
} from "../ha-automation-trigger-row";
import { handleChangeEvent } from "../ha-automation-trigger-row";
import { NumericStateTrigger, ForDict } from "../../../../../data/automation";
@customElement("ha-automation-trigger-numeric_state")
export default class HaNumericStateTrigger extends LitElement {

View File

@ -6,10 +6,9 @@ import { HomeAssistant } from "../../../../../types";
import {
handleChangeEvent,
TriggerElement,
StateTrigger,
ForDict,
} from "../ha-automation-trigger-row";
import { PolymerChangedEvent } from "../../../../../polymer-types";
import { StateTrigger, ForDict } from "../../../../../data/automation";
@customElement("ha-automation-trigger-state")
export class HaStateTrigger extends LitElement implements TriggerElement {

View File

@ -6,11 +6,11 @@ import { PaperRadioGroupElement } from "@polymer/paper-radio-group/paper-radio-g
import { LitElement, customElement, property, html } from "lit-element";
import { HomeAssistant } from "../../../../../types";
import {
SunTrigger,
handleChangeEvent,
TriggerElement,
} from "../ha-automation-trigger-row";
import { fireEvent } from "../../../../../common/dom/fire_event";
import { SunTrigger } from "../../../../../data/automation";
@customElement("ha-automation-trigger-sun")
export class HaSunTrigger extends LitElement implements TriggerElement {

View File

@ -1,10 +1,8 @@
import "../../../../../components/ha-textarea";
import { LitElement, property, html, customElement } from "lit-element";
import { HomeAssistant } from "../../../../../types";
import {
TemplateTrigger,
handleChangeEvent,
} from "../ha-automation-trigger-row";
import { handleChangeEvent } from "../ha-automation-trigger-row";
import { TemplateTrigger } from "../../../../../data/automation";
@customElement("ha-automation-trigger-template")
export class HaTemplateTrigger extends LitElement {

View File

@ -2,10 +2,10 @@ import "@polymer/paper-input/paper-input";
import { LitElement, html, property, customElement } from "lit-element";
import { HomeAssistant } from "../../../../../types";
import {
TimeTrigger,
handleChangeEvent,
TriggerElement,
} from "../ha-automation-trigger-row";
import { TimeTrigger } from "../../../../../data/automation";
@customElement("ha-automation-trigger-time")
export class HaTimeTrigger extends LitElement implements TriggerElement {

View File

@ -3,9 +3,9 @@ import { LitElement, property, html, customElement } from "lit-element";
import {
TriggerElement,
handleChangeEvent,
TimePatternTrigger,
} from "../ha-automation-trigger-row";
import { HomeAssistant } from "../../../../../types";
import { TimePatternTrigger } from "../../../../../data/automation";
@customElement("ha-automation-trigger-time_pattern")
export class HaTimePatternTrigger extends LitElement implements TriggerElement {

View File

@ -1,10 +1,8 @@
import "@polymer/paper-input/paper-input";
import { LitElement, customElement, property, html } from "lit-element";
import { HomeAssistant } from "../../../../../types";
import {
WebhookTrigger,
handleChangeEvent,
} from "../ha-automation-trigger-row";
import { handleChangeEvent } from "../ha-automation-trigger-row";
import { WebhookTrigger } from "../../../../../data/automation";
@customElement("ha-automation-trigger-webhook")
export class HaWebhookTrigger extends LitElement {

View File

@ -8,9 +8,9 @@ import { hasLocation } from "../../../../../common/entity/has_location";
import { computeStateDomain } from "../../../../../common/entity/compute_state_domain";
import { LitElement, property, html, customElement } from "lit-element";
import { HomeAssistant } from "../../../../../types";
import { ZoneTrigger } from "../ha-automation-trigger-row";
import { PolymerChangedEvent } from "../../../../../polymer-types";
import { fireEvent } from "../../../../../common/dom/fire_event";
import { ZoneTrigger } from "../../../../../data/automation";
function zoneAndLocationFilter(stateObj) {
return hasLocation(stateObj) && computeStateDomain(stateObj) !== "zone";

View File

@ -6,8 +6,8 @@ import "../../../components/ha-card";
import "../../../components/ha-textarea";
import "../automation/trigger/ha-automation-trigger";
import "../automation/condition/ha-automation-condition";
import Condition from "./condition/index";
import Script from "./script/index";
export default class Automation extends Component<any> {
@ -31,8 +31,11 @@ export default class Automation extends Component<any> {
this.props.onChange({ ...this.props.automation, trigger: ev.detail.value });
}
public conditionChanged(condition) {
this.props.onChange({ ...this.props.automation, condition });
public conditionChanged(ev: CustomEvent) {
this.props.onChange({
...this.props.automation,
condition: ev.detail.value,
});
}
public actionChanged(action) {
@ -117,11 +120,10 @@ export default class Automation extends Component<any> {
)}
</a>
</span>
<Condition
condition={condition || []}
onChange={this.conditionChanged}
<ha-automation-condition
conditions={condition || []}
onvalue-changed={this.conditionChanged}
hass={hass}
localize={localize}
/>
</ha-config-section>

View File

@ -1,108 +0,0 @@
import { h, Component } from "preact";
import "@polymer/paper-dropdown-menu/paper-dropdown-menu-light";
import "@polymer/paper-listbox/paper-listbox";
import "@polymer/paper-item/paper-item";
import YAMLTextArea from "../yaml_textarea";
import DeviceCondition from "./device";
import LogicalCondition from "./logical";
import NumericStateCondition from "./numeric_state";
import StateCondition from "./state";
import SunCondition from "./sun";
import TemplateCondition from "./template";
import TimeCondition from "./time";
import ZoneCondition from "./zone";
const TYPES = {
and: LogicalCondition,
device: DeviceCondition,
numeric_state: NumericStateCondition,
or: LogicalCondition,
state: StateCondition,
sun: SunCondition,
template: TemplateCondition,
time: TimeCondition,
zone: ZoneCondition,
};
const OPTIONS = Object.keys(TYPES).sort();
export default class ConditionEdit extends Component<any> {
constructor() {
super();
this.typeChanged = this.typeChanged.bind(this);
this.onYamlChange = this.onYamlChange.bind(this);
}
public typeChanged(ev) {
const type = ev.target.selectedItem.attributes.condition.value;
if (type !== this.props.condition.condition) {
this.props.onChange(this.props.index, {
condition: type,
...TYPES[type].defaultConfig,
});
}
}
public render({ index, condition, onChange, hass, localize, yamlMode }) {
// tslint:disable-next-line: variable-name
const Comp = TYPES[condition.condition];
const selected = OPTIONS.indexOf(condition.condition);
if (yamlMode || !Comp) {
return (
<div style="margin-right: 24px;">
{!Comp && (
<div>
{localize(
"ui.panel.config.automation.editor.conditions.unsupported_condition",
"condition",
condition.condition
)}
</div>
)}
<YAMLTextArea value={condition} onChange={this.onYamlChange} />
</div>
);
}
return (
<div>
<paper-dropdown-menu-light
label={localize(
"ui.panel.config.automation.editor.conditions.type_select"
)}
no-animations
>
<paper-listbox
slot="dropdown-content"
selected={selected}
oniron-select={this.typeChanged}
>
{OPTIONS.map((opt) => (
<paper-item condition={opt}>
{localize(
`ui.panel.config.automation.editor.conditions.type.${opt}.label`
)}
</paper-item>
))}
</paper-listbox>
</paper-dropdown-menu-light>
<Comp
index={index}
condition={condition}
onChange={onChange}
hass={hass}
localize={localize}
/>
</div>
);
}
private onYamlChange(condition) {
this.props.onChange(this.props.index, condition);
}
}

View File

@ -1,86 +0,0 @@
import { h, Component } from "preact";
import "@polymer/paper-menu-button/paper-menu-button";
import "@polymer/paper-icon-button/paper-icon-button";
import "@polymer/paper-listbox/paper-listbox";
import "@polymer/paper-item/paper-item";
import "../../../../components/ha-card";
import ConditionEdit from "./condition_edit";
export default class ConditionRow extends Component<any> {
public state: { yamlMode: boolean };
constructor() {
super();
this.state = {
yamlMode: false,
};
this.onDelete = this.onDelete.bind(this);
this.switchYamlMode = this.switchYamlMode.bind(this);
}
public onDelete() {
// eslint-disable-next-line
if (
confirm(
this.props.localize(
"ui.panel.config.automation.editor.conditions.delete_confirm"
)
)
) {
this.props.onChange(this.props.index, null);
}
}
public render(props, { yamlMode }) {
return (
<ha-card>
<div class="card-content">
<div class="card-menu" style="z-index: 3">
<paper-menu-button
no-animations
horizontal-align="right"
horizontal-offset="-5"
vertical-offset="-5"
close-on-activate
>
<paper-icon-button
icon="hass:dots-vertical"
slot="dropdown-trigger"
/>
<paper-listbox slot="dropdown-content">
<paper-item onTap={this.switchYamlMode}>
{yamlMode
? props.localize(
"ui.panel.config.automation.editor.edit_ui"
)
: props.localize(
"ui.panel.config.automation.editor.edit_yaml"
)}
</paper-item>
<paper-item disabled>
{props.localize(
"ui.panel.config.automation.editor.conditions.duplicate"
)}
</paper-item>
<paper-item onTap={this.onDelete}>
{props.localize(
"ui.panel.config.automation.editor.conditions.delete"
)}
</paper-item>
</paper-listbox>
</paper-menu-button>
</div>
<ConditionEdit {...props} yamlMode={yamlMode} />
</div>
</ha-card>
);
}
private switchYamlMode() {
this.setState({
yamlMode: !this.state.yamlMode,
});
}
}

View File

@ -1,133 +0,0 @@
import { h } from "preact";
import "../../../../components/device/ha-device-picker";
import "../../../../components/device/ha-device-condition-picker";
import "../../../../components/ha-form/ha-form";
import {
fetchDeviceConditionCapabilities,
deviceAutomationsEqual,
} from "../../../../data/device_automation";
import { AutomationComponent } from "../automation-component";
export default class DeviceCondition extends AutomationComponent<any, any> {
private _origCondition;
constructor() {
super();
this.devicePicked = this.devicePicked.bind(this);
this.deviceConditionPicked = this.deviceConditionPicked.bind(this);
this._extraFieldsChanged = this._extraFieldsChanged.bind(this);
this.state = { device_id: undefined, capabilities: undefined };
}
public devicePicked(ev) {
if (!this.initialized) {
return;
}
this.setState({ ...this.state, device_id: ev.target.value });
}
public deviceConditionPicked(ev) {
if (!this.initialized) {
return;
}
let condition = ev.target.value;
if (
this._origCondition &&
deviceAutomationsEqual(this._origCondition, condition)
) {
condition = this._origCondition;
}
this.props.onChange(this.props.index, condition);
}
/* eslint-disable camelcase */
public render({ condition, hass }, { device_id, capabilities }) {
if (device_id === undefined) {
device_id = condition.device_id;
}
const extraFieldsData =
capabilities && capabilities.extra_fields
? capabilities.extra_fields.map((item) => {
return { [item.name]: this.props.condition[item.name] };
})
: undefined;
return (
<div>
<ha-device-picker
value={device_id}
onChange={this.devicePicked}
hass={hass}
label="Device"
/>
<ha-device-condition-picker
value={condition}
deviceId={device_id}
onChange={this.deviceConditionPicked}
hass={hass}
label="Condition"
/>
{extraFieldsData && (
<ha-form
data={Object.assign({}, ...extraFieldsData)}
schema={this.state.capabilities.extra_fields}
computeLabel={this._extraFieldsComputeLabelCallback(hass.localize)}
onvalue-changed={this._extraFieldsChanged}
/>
)}
</div>
);
}
public componentDidMount() {
this.initialized = true;
if (!this.state.capabilities) {
this._getCapabilities();
}
if (this.props.condition) {
this._origCondition = this.props.condition;
}
}
public componentDidUpdate(prevProps) {
if (!deviceAutomationsEqual(prevProps.condition, this.props.condition)) {
this._getCapabilities();
}
}
private async _getCapabilities() {
const condition = this.props.condition;
const capabilities = condition.domain
? await fetchDeviceConditionCapabilities(this.props.hass, condition)
: null;
this.setState({ ...this.state, capabilities });
}
private _extraFieldsChanged(ev) {
if (!this.initialized) {
return;
}
this.props.onChange(this.props.index, {
...this.props.condition,
...ev.detail.value,
});
}
private _extraFieldsComputeLabelCallback(localize) {
// Returns a callback for ha-form to calculate labels per schema object
return (schema) =>
localize(
`ui.panel.config.automation.editor.condition.type.device.extra_fields.${schema.name}`
) || schema.name;
}
}
(DeviceCondition as any).defaultConfig = {
device_id: "",
domain: "",
entity_id: "",
};

View File

@ -1,57 +0,0 @@
import { h, Component } from "preact";
import "@material/mwc-button";
import "../../../../components/ha-card";
import ConditionRow from "./condition_row";
export default class Condition extends Component<any> {
constructor() {
super();
this.addCondition = this.addCondition.bind(this);
this.conditionChanged = this.conditionChanged.bind(this);
}
public addCondition() {
const condition = this.props.condition.concat({
condition: "state",
});
this.props.onChange(condition);
}
public conditionChanged(index, newValue) {
const condition = this.props.condition.concat();
if (newValue === null) {
condition.splice(index, 1);
} else {
condition[index] = newValue;
}
this.props.onChange(condition);
}
public render({ condition, hass, localize }) {
return (
<div class="triggers">
{condition.map((cnd, idx) => (
<ConditionRow
index={idx}
condition={cnd}
onChange={this.conditionChanged}
hass={hass}
localize={localize}
/>
))}
<ha-card>
<div class="card-actions add-card">
<mwc-button onTap={this.addCondition}>
{localize("ui.panel.config.automation.editor.conditions.add")}
</mwc-button>
</div>
</ha-card>
</div>
);
}
}

View File

@ -1,39 +0,0 @@
import { h } from "preact";
import Condition from "./index";
import { AutomationComponent } from "../automation-component";
export default class LogicalCondition extends AutomationComponent<any> {
constructor() {
super();
this.conditionChanged = this.conditionChanged.bind(this);
}
public conditionChanged(conditions) {
if (!this.initialized) {
return;
}
this.props.onChange(this.props.index, {
...this.props.condition,
conditions,
});
}
/* eslint-disable camelcase */
public render({ condition, hass, localize }) {
return (
<div>
<Condition
condition={condition.conditions || []}
onChange={this.conditionChanged}
hass={hass}
localize={localize}
/>
</div>
);
}
}
(LogicalCondition as any).defaultConfig = {
conditions: [{ condition: "state" }],
};

View File

@ -1,71 +0,0 @@
import { h } from "preact";
import "@polymer/paper-input/paper-input";
import "../../../../components/ha-textarea";
import "../../../../components/entity/ha-entity-picker";
import { onChangeEvent } from "../../../../common/preact/event";
import { AutomationComponent } from "../automation-component";
export default class NumericStateCondition extends AutomationComponent<any> {
private onChange: (obj: any) => void;
constructor() {
super();
this.onChange = onChangeEvent.bind(this, "condition");
this.entityPicked = this.entityPicked.bind(this);
}
public entityPicked(ev) {
if (!this.initialized) {
return;
}
this.props.onChange(this.props.index, {
...this.props.condition,
entity_id: ev.target.value,
});
}
/* eslint-disable camelcase */
public render({ condition, hass, localize }) {
const { value_template, entity_id, below, above } = condition;
return (
<div>
<ha-entity-picker
value={entity_id}
onChange={this.entityPicked}
hass={hass}
allowCustomEntity
/>
<paper-input
label={localize(
"ui.panel.config.automation.editor.conditions.type.numeric_state.above"
)}
name="above"
value={above}
onvalue-changed={this.onChange}
/>
<paper-input
label={localize(
"ui.panel.config.automation.editor.conditions.type.numeric_state.below"
)}
name="below"
value={below}
onvalue-changed={this.onChange}
/>
<ha-textarea
label={localize(
"ui.panel.config.automation.editor.conditions.type.numeric_state.value_template"
)}
name="value_template"
value={value_template}
onvalue-changed={this.onChange}
dir="ltr"
/>
</div>
);
}
}
(NumericStateCondition as any).defaultConfig = {
entity_id: "",
};

View File

@ -1,56 +0,0 @@
import { h } from "preact";
import "@polymer/paper-input/paper-input";
import "../../../../components/entity/ha-entity-picker";
import { onChangeEvent } from "../../../../common/preact/event";
import { AutomationComponent } from "../automation-component";
export default class StateCondition extends AutomationComponent<any> {
private onChange: (obj: any) => void;
constructor() {
super();
this.onChange = onChangeEvent.bind(this, "condition");
this.entityPicked = this.entityPicked.bind(this);
}
public entityPicked(ev) {
if (!this.initialized) {
return;
}
this.props.onChange(this.props.index, {
...this.props.condition,
entity_id: ev.target.value,
});
}
/* eslint-disable camelcase */
public render({ condition, hass, localize }) {
const { entity_id, state } = condition;
const cndFor = condition.for;
return (
<div>
<ha-entity-picker
value={entity_id}
onChange={this.entityPicked}
hass={hass}
allowCustomEntity
/>
<paper-input
label={localize(
"ui.panel.config.automation.editor.conditions.type.state.state"
)}
name="state"
value={state}
onvalue-changed={this.onChange}
/>
{cndFor && <pre>For: {JSON.stringify(cndFor, null, 2)}</pre>}
</div>
);
}
}
(StateCondition as any).defaultConfig = {
entity_id: "",
state: "",
};

View File

@ -1,112 +0,0 @@
import { h } from "preact";
import "@polymer/paper-input/paper-input";
import "@polymer/paper-radio-button/paper-radio-button";
import "@polymer/paper-radio-group/paper-radio-group";
import { onChangeEvent } from "../../../../common/preact/event";
import { AutomationComponent } from "../automation-component";
export default class SunCondition extends AutomationComponent<any> {
private onChange: (obj: any) => void;
private afterPicked: (obj: any) => void;
private beforePicked: (obj: any) => void;
constructor() {
super();
this.onChange = onChangeEvent.bind(this, "condition");
this.afterPicked = this.radioGroupPicked.bind(this, "after");
this.beforePicked = this.radioGroupPicked.bind(this, "before");
}
public radioGroupPicked(key, ev) {
if (!this.initialized) {
return;
}
const condition = { ...this.props.condition };
if (ev.target.selected) {
condition[key] = ev.target.selected;
} else {
delete condition[key];
}
this.props.onChange(this.props.index, condition);
}
public render({ condition, localize }) {
/* eslint-disable camelcase */
const { after, after_offset, before, before_offset } = condition;
return (
<div>
<label id="beforelabel">
{localize(
"ui.panel.config.automation.editor.conditions.type.sun.before"
)}
</label>
<paper-radio-group
allow-empty-selection
selected={before}
aria-labelledby="beforelabel"
onpaper-radio-group-changed={this.beforePicked}
>
<paper-radio-button name="sunrise">
{localize(
"ui.panel.config.automation.editor.conditions.type.sun.sunrise"
)}
</paper-radio-button>
<paper-radio-button name="sunset">
{localize(
"ui.panel.config.automation.editor.conditions.type.sun.sunset"
)}
</paper-radio-button>
</paper-radio-group>
<paper-input
label={localize(
"ui.panel.config.automation.editor.conditions.type.sun.before_offset"
)}
name="before_offset"
value={before_offset}
onvalue-changed={this.onChange}
disabled={before === undefined}
/>
<label id="afterlabel">
{localize(
"ui.panel.config.automation.editor.conditions.type.sun.after"
)}
</label>
<paper-radio-group
allow-empty-selection
selected={after}
aria-labelledby="afterlabel"
onpaper-radio-group-changed={this.afterPicked}
>
<paper-radio-button name="sunrise">
{localize(
"ui.panel.config.automation.editor.conditions.type.sun.sunrise"
)}
</paper-radio-button>
<paper-radio-button name="sunset">
{localize(
"ui.panel.config.automation.editor.conditions.type.sun.sunset"
)}
</paper-radio-button>
</paper-radio-group>
<paper-input
label={localize(
"ui.panel.config.automation.editor.conditions.type.sun.after_offset"
)}
name="after_offset"
value={after_offset}
onvalue-changed={this.onChange}
disabled={after === undefined}
/>
</div>
);
}
}
(SunCondition as any).defaultConfig = {};

View File

@ -1,36 +0,0 @@
import { h } from "preact";
import "../../../../components/ha-textarea";
import { onChangeEvent } from "../../../../common/preact/event";
import { AutomationComponent } from "../automation-component";
export default class TemplateCondition extends AutomationComponent<any> {
private onChange: (obj: any) => void;
constructor() {
super();
this.onChange = onChangeEvent.bind(this, "condition");
}
public render({ condition, localize }) {
/* eslint-disable camelcase */
const { value_template } = condition;
return (
<div>
<ha-textarea
label={localize(
"ui.panel.config.automation.editor.conditions.type.template.value_template"
)}
name="value_template"
value={value_template}
onvalue-changed={this.onChange}
dir="ltr"
/>
</div>
);
}
}
(TemplateCondition as any).defaultConfig = {
value_template: "",
};

View File

@ -1,41 +0,0 @@
import { h } from "preact";
import "@polymer/paper-input/paper-input";
import { onChangeEvent } from "../../../../common/preact/event";
import { AutomationComponent } from "../automation-component";
export default class TimeCondition extends AutomationComponent<any> {
private onChange: (obj: any) => void;
constructor() {
super();
this.onChange = onChangeEvent.bind(this, "condition");
}
/* eslint-disable camelcase */
public render({ condition, localize }) {
const { after, before } = condition;
return (
<div>
<paper-input
label={localize(
"ui.panel.config.automation.editor.conditions.type.time.after"
)}
name="after"
value={after}
onvalue-changed={this.onChange}
/>
<paper-input
label={localize(
"ui.panel.config.automation.editor.conditions.type.time.before"
)}
name="before"
value={before}
onvalue-changed={this.onChange}
/>
</div>
);
}
}
(TimeCondition as any).defaultConfig = {};

View File

@ -1,73 +0,0 @@
import { h } from "preact";
import "../../../../components/entity/ha-entity-picker";
import { hasLocation } from "../../../../common/entity/has_location";
import { computeStateDomain } from "../../../../common/entity/compute_state_domain";
import { AutomationComponent } from "../automation-component";
function zoneAndLocationFilter(stateObj) {
return hasLocation(stateObj) && computeStateDomain(stateObj) !== "zone";
}
export default class ZoneCondition extends AutomationComponent<any> {
constructor() {
super();
this.entityPicked = this.entityPicked.bind(this);
this.zonePicked = this.zonePicked.bind(this);
}
public entityPicked(ev) {
if (!this.initialized) {
return;
}
this.props.onChange(this.props.index, {
...this.props.condition,
entity_id: ev.target.value,
});
}
public zonePicked(ev) {
if (!this.initialized) {
return;
}
this.props.onChange(this.props.index, {
...this.props.condition,
zone: ev.target.value,
});
}
/* eslint-disable camelcase */
public render({ condition, hass, localize }) {
const { entity_id, zone } = condition;
return (
<div>
<ha-entity-picker
label={localize(
"ui.panel.config.automation.editor.conditions.type.zone.entity"
)}
value={entity_id}
onChange={this.entityPicked}
hass={hass}
allowCustomEntity
entityFilter={zoneAndLocationFilter}
/>
<ha-entity-picker
label={localize(
"ui.panel.config.automation.editor.conditions.type.zone.zone"
)}
value={zone}
onChange={this.zonePicked}
hass={hass}
allowCustomEntity
includeDomains={["zone"]}
/>
</div>
);
}
}
(ZoneCondition as any).defaultConfig = {
entity_id: "",
zone: "",
};

View File

@ -24,6 +24,8 @@ declare global {
"ha-service-picker": any;
"mwc-button": any;
"ha-automation-trigger": any;
"ha-automation-condition": any;
"ha-automation-condition-editor": any;
"ha-device-trigger-picker": any;
"ha-device-action-picker": any;
"ha-form": any;

View File

@ -1,24 +1,32 @@
import { h, Component } from "preact";
import StateCondition from "../condition/state";
import ConditionEdit from "../condition/condition_edit";
import "../../automation/condition/ha-automation-condition-editor";
export default class ConditionAction extends Component<any> {
constructor() {
super();
this.conditionChanged = this.conditionChanged.bind(this);
}
public conditionChanged(ev) {
this.props.onChange(this.props.index, ev.detail.value);
}
// eslint-disable-next-line
public render({ action, index, onChange, hass, localize }) {
public render({ action, hass }) {
return (
<ConditionEdit
condition={action}
onChange={onChange}
index={index}
hass={hass}
localize={localize}
/>
<div>
<ha-automation-condition-editor
condition={action}
onvalue-changed={this.conditionChanged}
hass={hass}
/>
</div>
);
}
}
(ConditionAction as any).defaultConfig = {
condition: "state",
...(StateCondition as any).defaultConfig,
};