From 5217d427e92d7c878c093b53883f121cb1fcc643 Mon Sep 17 00:00:00 2001 From: karwosts <32912880+karwosts@users.noreply.github.com> Date: Wed, 31 May 2023 05:28:16 -0700 Subject: [PATCH] Support to|from null in UI for ha-automation-trigger-state (#15071) Co-authored-by: Bram Kragten --- .../entity/ha-entity-state-picker.ts | 17 +++++-- .../ha-selector/ha-selector-state.ts | 1 + src/data/automation_i18n.ts | 8 +++ src/data/selector.ts | 1 + .../types/ha-automation-trigger-state.ts | 49 +++++++++++++++++-- src/translations/en.json | 3 +- 6 files changed, 70 insertions(+), 9 deletions(-) diff --git a/src/components/entity/ha-entity-state-picker.ts b/src/components/entity/ha-entity-state-picker.ts index 588269ecb7..7b92f63aa2 100644 --- a/src/components/entity/ha-entity-state-picker.ts +++ b/src/components/entity/ha-entity-state-picker.ts @@ -19,6 +19,8 @@ class HaEntityStatePicker extends LitElement { @property() public attribute?: string; + @property() public extraOptions?: any[]; + @property({ type: Boolean }) public autofocus = false; @property({ type: Boolean }) public disabled = false; @@ -43,10 +45,16 @@ class HaEntityStatePicker extends LitElement { } protected updated(changedProps: PropertyValues) { - if (changedProps.has("_opened") && this._opened) { + if ( + (changedProps.has("_opened") && this._opened) || + changedProps.has("entityId") || + changedProps.has("attribute") || + changedProps.has("extraOptions") + ) { const state = this.entityId ? this.hass.states[this.entityId] : undefined; - (this._comboBox as any).items = - this.entityId && state + (this._comboBox as any).items = [ + ...(this.extraOptions ?? []), + ...(this.entityId && state ? getStates(state, this.attribute).map((key) => ({ value: key, label: !this.attribute @@ -66,7 +74,8 @@ class HaEntityStatePicker extends LitElement { key ), })) - : []; + : []), + ]; } } diff --git a/src/components/ha-selector/ha-selector-state.ts b/src/components/ha-selector/ha-selector-state.ts index a28628ed86..4b16c8e8b0 100644 --- a/src/components/ha-selector/ha-selector-state.ts +++ b/src/components/ha-selector/ha-selector-state.ts @@ -34,6 +34,7 @@ export class HaSelectorState extends SubscribeMixin(LitElement) { this.context?.filter_entity} .attribute=${this.selector.state?.attribute || this.context?.filter_attribute} + .extraOptions=${this.selector.state?.extra_options} .value=${this.value} .label=${this.label} .helper=${this.helper} diff --git a/src/data/automation_i18n.ts b/src/data/automation_i18n.ts index b6e3a0e378..d989b8617f 100644 --- a/src/data/automation_i18n.ts +++ b/src/data/automation_i18n.ts @@ -301,6 +301,14 @@ export const describeTrigger = ( } } + if ( + !trigger.attribute && + trigger.from === undefined && + trigger.to === undefined + ) { + base += " state or any attributes"; + } + if (trigger.for) { const duration = describeDuration(trigger.for); if (duration) { diff --git a/src/data/selector.ts b/src/data/selector.ts index 7c75a806bf..6523ede4f6 100644 --- a/src/data/selector.ts +++ b/src/data/selector.ts @@ -295,6 +295,7 @@ export interface SelectSelector { export interface StateSelector { state: { + extra_options?: { label: string; value: any }[]; entity_id?: string; attribute?: string; } | null; diff --git a/src/panels/config/automation/trigger/types/ha-automation-trigger-state.ts b/src/panels/config/automation/trigger/types/ha-automation-trigger-state.ts index 9c23f45caf..61904a424f 100644 --- a/src/panels/config/automation/trigger/types/ha-automation-trigger-state.ts +++ b/src/panels/config/automation/trigger/types/ha-automation-trigger-state.ts @@ -5,6 +5,7 @@ import { assert, assign, literal, + nullable, number, object, optional, @@ -12,6 +13,7 @@ import { union, } from "superstruct"; import memoizeOne from "memoize-one"; +import type { LocalizeFunc } from "../../../../../common/translations/localize"; import { ensureArray } from "../../../../../common/array/ensure-array"; import { fireEvent } from "../../../../../common/dom/fire_event"; import { hasTemplate } from "../../../../../common/string/has-template"; @@ -30,12 +32,14 @@ const stateTriggerStruct = assign( platform: literal("state"), entity_id: optional(union([string(), array(string())])), attribute: optional(string()), - from: optional(string()), - to: optional(string()), + from: optional(nullable(string())), + to: optional(nullable(string())), for: optional(union([number(), string(), forDictStruct])), }) ); +const ANY_STATE_VALUE = "__ANY_STATE_IGNORE_ATTRIBUTES__"; + @customElement("ha-automation-trigger-state") export class HaStateTrigger extends LitElement implements TriggerElement { @property({ attribute: false }) public hass!: HomeAssistant; @@ -49,7 +53,7 @@ export class HaStateTrigger extends LitElement implements TriggerElement { } private _schema = memoizeOne( - (entityId, attribute) => + (localize: LocalizeFunc, entityId, attribute) => [ { name: "entity_id", @@ -117,6 +121,16 @@ export class HaStateTrigger extends LitElement implements TriggerElement { name: "from", selector: { state: { + extra_options: (attribute + ? [] + : [ + { + label: localize( + "ui.panel.config.automation.editor.triggers.type.state.any_state_ignore_attributes" + ), + value: ANY_STATE_VALUE, + }, + ]) as any, entity_id: entityId ? entityId[0] : undefined, attribute: attribute, }, @@ -126,6 +140,16 @@ export class HaStateTrigger extends LitElement implements TriggerElement { name: "to", selector: { state: { + extra_options: (attribute + ? [] + : [ + { + label: localize( + "ui.panel.config.automation.editor.triggers.type.state.any_state_ignore_attributes" + ), + value: ANY_STATE_VALUE, + }, + ]) as any, entity_id: entityId ? entityId[0] : undefined, attribute: attribute, }, @@ -172,7 +196,17 @@ export class HaStateTrigger extends LitElement implements TriggerElement { entity_id: ensureArray(this.trigger.entity_id), for: trgFor, }; - const schema = this._schema(this.trigger.entity_id, this.trigger.attribute); + if (!data.attribute && data.to === null) { + data.to = ANY_STATE_VALUE; + } + if (!data.attribute && data.from === null) { + data.from = ANY_STATE_VALUE; + } + const schema = this._schema( + this.hass.localize, + this.trigger.entity_id, + this.trigger.attribute + ); return html` newTrigger[key] === undefined || newTrigger[key] === "" ? delete newTrigger[key] diff --git a/src/translations/en.json b/src/translations/en.json index 2b06405594..2ca54ecd4a 100755 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -2301,7 +2301,8 @@ "attribute": "Attribute (optional)", "from": "From (optional)", "for": "For", - "to": "To (optional)" + "to": "To (optional)", + "any_state_ignore_attributes": "Any state (ignoring attribute changes)" }, "homeassistant": { "label": "Home Assistant",