mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-24 09:46:36 +00:00
Add sensor offset to time trigger UI (#21957)
* Add sensor offset to time trigger UI * refactor long expression * memoize data * fix for trigger platform migration
This commit is contained in:
parent
82b50a1c5d
commit
79c71cbe48
@ -167,7 +167,7 @@ export interface TagTrigger extends BaseTrigger {
|
||||
|
||||
export interface TimeTrigger extends BaseTrigger {
|
||||
trigger: "time";
|
||||
at: string;
|
||||
at: string | { entity_id: string; offset?: string };
|
||||
}
|
||||
|
||||
export interface TemplateTrigger extends BaseTrigger {
|
||||
|
@ -8,6 +8,7 @@ import {
|
||||
import secondsToDuration from "../common/datetime/seconds_to_duration";
|
||||
import { computeAttributeNameDisplay } from "../common/entity/compute_attribute_display";
|
||||
import { computeStateName } from "../common/entity/compute_state_name";
|
||||
import { isValidEntityId } from "../common/entity/valid_entity_id";
|
||||
import type { HomeAssistant } from "../types";
|
||||
import { Condition, ForDict, Trigger } from "./automation";
|
||||
import {
|
||||
@ -371,13 +372,22 @@ const tryDescribeTrigger = (
|
||||
|
||||
// Time Trigger
|
||||
if (trigger.trigger === "time" && trigger.at) {
|
||||
const result = ensureArray(trigger.at).map((at) =>
|
||||
typeof at !== "string"
|
||||
? at
|
||||
: at.includes(".")
|
||||
? `entity ${hass.states[at] ? computeStateName(hass.states[at]) : at}`
|
||||
: localizeTimeString(at, hass.locale, hass.config)
|
||||
);
|
||||
const result = ensureArray(trigger.at).map((at) => {
|
||||
if (typeof at === "string") {
|
||||
if (isValidEntityId(at)) {
|
||||
return `entity ${hass.states[at] ? computeStateName(hass.states[at]) : at}`;
|
||||
}
|
||||
return localizeTimeString(at, hass.locale, hass.config);
|
||||
}
|
||||
const entityStr = `entity ${hass.states[at.entity_id] ? computeStateName(hass.states[at.entity_id]) : at.entity_id}`;
|
||||
const offsetStr = at.offset
|
||||
? " " +
|
||||
hass.localize(`${triggerTranslationBaseKey}.time.offset_by`, {
|
||||
offset: describeDuration(hass.locale, at.offset),
|
||||
})
|
||||
: "";
|
||||
return `${entityStr}${offsetStr}`;
|
||||
});
|
||||
|
||||
return hass.localize(`${triggerTranslationBaseKey}.time.description.full`, {
|
||||
time: formatListWithOrs(hass.locale, result),
|
||||
|
@ -9,6 +9,9 @@ import type { TimeTrigger } from "../../../../../data/automation";
|
||||
import type { HomeAssistant } from "../../../../../types";
|
||||
import type { TriggerElement } from "../ha-automation-trigger-row";
|
||||
|
||||
const MODE_TIME = "time";
|
||||
const MODE_ENTITY = "entity";
|
||||
|
||||
@customElement("ha-automation-trigger-time")
|
||||
export class HaTimeTrigger extends LitElement implements TriggerElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
@ -17,48 +20,60 @@ export class HaTimeTrigger extends LitElement implements TriggerElement {
|
||||
|
||||
@property({ type: Boolean }) public disabled = false;
|
||||
|
||||
@state() private _inputMode?: boolean;
|
||||
@state() private _inputMode:
|
||||
| undefined
|
||||
| typeof MODE_TIME
|
||||
| typeof MODE_ENTITY;
|
||||
|
||||
public static get defaultConfig(): TimeTrigger {
|
||||
return { trigger: "time", at: "" };
|
||||
}
|
||||
|
||||
private _schema = memoizeOne(
|
||||
(localize: LocalizeFunc, inputMode?: boolean) => {
|
||||
const atSelector = inputMode
|
||||
? {
|
||||
entity: {
|
||||
filter: [
|
||||
{ domain: "input_datetime" },
|
||||
{ domain: "sensor", device_class: "timestamp" },
|
||||
],
|
||||
},
|
||||
}
|
||||
: { time: {} };
|
||||
|
||||
return [
|
||||
(
|
||||
localize: LocalizeFunc,
|
||||
inputMode: typeof MODE_TIME | typeof MODE_ENTITY,
|
||||
showOffset: boolean
|
||||
) =>
|
||||
[
|
||||
{
|
||||
name: "mode",
|
||||
type: "select",
|
||||
required: true,
|
||||
options: [
|
||||
[
|
||||
"value",
|
||||
MODE_TIME,
|
||||
localize(
|
||||
"ui.panel.config.automation.editor.triggers.type.time.type_value"
|
||||
),
|
||||
],
|
||||
[
|
||||
"input",
|
||||
MODE_ENTITY,
|
||||
localize(
|
||||
"ui.panel.config.automation.editor.triggers.type.time.type_input"
|
||||
),
|
||||
],
|
||||
],
|
||||
},
|
||||
{ name: "at", selector: atSelector },
|
||||
] as const;
|
||||
}
|
||||
...(inputMode === MODE_TIME
|
||||
? ([{ name: "time", selector: { time: {} } }] as const)
|
||||
: ([
|
||||
{
|
||||
name: "entity",
|
||||
selector: {
|
||||
entity: {
|
||||
filter: [
|
||||
{ domain: "input_datetime" },
|
||||
{ domain: "sensor", device_class: "timestamp" },
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
] as const)),
|
||||
...(showOffset
|
||||
? ([{ name: "offset", selector: { text: {} } }] as const)
|
||||
: ([] as const)),
|
||||
] as const
|
||||
);
|
||||
|
||||
public willUpdate(changedProperties: PropertyValues) {
|
||||
@ -75,23 +90,46 @@ export class HaTimeTrigger extends LitElement implements TriggerElement {
|
||||
}
|
||||
}
|
||||
|
||||
private _data = memoizeOne(
|
||||
(
|
||||
inputMode: undefined | typeof MODE_ENTITY | typeof MODE_TIME,
|
||||
at:
|
||||
| string
|
||||
| { entity_id: string | undefined; offset?: string | undefined }
|
||||
): {
|
||||
mode: typeof MODE_TIME | typeof MODE_ENTITY;
|
||||
entity: string | undefined;
|
||||
time: string | undefined;
|
||||
offset: string | undefined;
|
||||
} => {
|
||||
const entity =
|
||||
typeof at === "object"
|
||||
? at.entity_id
|
||||
: at?.startsWith("input_datetime.") || at?.startsWith("sensor.")
|
||||
? at
|
||||
: undefined;
|
||||
const time = entity ? undefined : (at as string | undefined);
|
||||
const offset = typeof at === "object" ? at.offset : undefined;
|
||||
const mode = inputMode ?? (entity ? MODE_ENTITY : MODE_TIME);
|
||||
return {
|
||||
mode,
|
||||
entity,
|
||||
time,
|
||||
offset,
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
protected render() {
|
||||
const at = this.trigger.at;
|
||||
|
||||
if (Array.isArray(at)) {
|
||||
return nothing;
|
||||
}
|
||||
|
||||
const inputMode =
|
||||
this._inputMode ??
|
||||
(at?.startsWith("input_datetime.") || at?.startsWith("sensor."));
|
||||
|
||||
const schema = this._schema(this.hass.localize, inputMode);
|
||||
|
||||
const data = {
|
||||
mode: inputMode ? "input" : "value",
|
||||
...this.trigger,
|
||||
};
|
||||
const data = this._data(this._inputMode, at);
|
||||
const showOffset =
|
||||
data.mode === MODE_ENTITY && data.entity?.startsWith("sensor.");
|
||||
const schema = this._schema(this.hass.localize, data.mode, !!showOffset);
|
||||
|
||||
return html`
|
||||
<ha-form
|
||||
@ -107,26 +145,43 @@ export class HaTimeTrigger extends LitElement implements TriggerElement {
|
||||
|
||||
private _valueChanged(ev: CustomEvent): void {
|
||||
ev.stopPropagation();
|
||||
const newValue = ev.detail.value;
|
||||
|
||||
this._inputMode = newValue.mode === "input";
|
||||
delete newValue.mode;
|
||||
|
||||
Object.keys(newValue).forEach((key) =>
|
||||
newValue[key] === undefined || newValue[key] === ""
|
||||
? delete newValue[key]
|
||||
: {}
|
||||
);
|
||||
|
||||
fireEvent(this, "value-changed", { value: newValue });
|
||||
const newValue = { ...ev.detail.value };
|
||||
this._inputMode = newValue.mode;
|
||||
if (newValue.mode === MODE_TIME) {
|
||||
delete newValue.entity;
|
||||
delete newValue.offset;
|
||||
} else {
|
||||
delete newValue.time;
|
||||
if (!newValue.entity?.startsWith("sensor.")) {
|
||||
delete newValue.offset;
|
||||
}
|
||||
}
|
||||
fireEvent(this, "value-changed", {
|
||||
value: {
|
||||
...this.trigger,
|
||||
at: newValue.offset
|
||||
? {
|
||||
entity_id: newValue.entity,
|
||||
offset: newValue.offset,
|
||||
}
|
||||
: newValue.entity || newValue.time,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
private _computeLabelCallback = (
|
||||
schema: SchemaUnion<ReturnType<typeof this._schema>>
|
||||
): string =>
|
||||
this.hass.localize(
|
||||
): string => {
|
||||
switch (schema.name) {
|
||||
case "time":
|
||||
return this.hass.localize(
|
||||
`ui.panel.config.automation.editor.triggers.type.time.at`
|
||||
);
|
||||
}
|
||||
return this.hass.localize(
|
||||
`ui.panel.config.automation.editor.triggers.type.time.${schema.name}`
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
declare global {
|
||||
|
@ -3054,6 +3054,9 @@
|
||||
"type_input": "Value of a date/time helper or timestamp-class sensor",
|
||||
"label": "Time",
|
||||
"at": "At time",
|
||||
"offset": "[%key:ui::panel::config::automation::editor::triggers::type::sun::offset%]",
|
||||
"entity": "Entity with timestamp",
|
||||
"offset_by": "offset by {offset}",
|
||||
"mode": "Mode",
|
||||
"description": {
|
||||
"picker": "At a specific time, or on a specific date.",
|
||||
|
Loading…
x
Reference in New Issue
Block a user