diff --git a/gallery/src/pages/automation/describe-action.ts b/gallery/src/pages/automation/describe-action.ts index dd3d6c6e93..286a25dc3d 100644 --- a/gallery/src/pages/automation/describe-action.ts +++ b/gallery/src/pages/automation/describe-action.ts @@ -62,6 +62,17 @@ const ACTIONS = [ entity_id: "input_boolean.toggle_4", }, }, + { + parallel: [ + { scene: "scene.kitchen_morning" }, + { + service: "media_player.play_media", + target: { entity_id: "media_player.living_room" }, + data: { media_content_id: "", media_content_type: "" }, + metadata: { title: "Happy Song" }, + }, + ], + }, ]; @customElement("demo-automation-describe-action") diff --git a/gallery/src/pages/automation/editor-action.ts b/gallery/src/pages/automation/editor-action.ts index 1f7a0d8206..6d675f974c 100644 --- a/gallery/src/pages/automation/editor-action.ts +++ b/gallery/src/pages/automation/editor-action.ts @@ -20,6 +20,7 @@ import { HaWaitForTriggerAction } from "../../../../src/panels/config/automation import { HaWaitAction } from "../../../../src/panels/config/automation/action/types/ha-automation-action-wait_template"; import { Action } from "../../../../src/data/script"; import { HaConditionAction } from "../../../../src/panels/config/automation/action/types/ha-automation-action-condition"; +import { HaParallelAction } from "../../../../src/panels/config/automation/action/types/ha-automation-action-parallel"; const SCHEMAS: { name: string; actions: Action[] }[] = [ { name: "Event", actions: [HaEventAction.defaultConfig] }, @@ -33,6 +34,7 @@ const SCHEMAS: { name: string; actions: Action[] }[] = [ { name: "Repeat", actions: [HaRepeatAction.defaultConfig] }, { name: "Choose", actions: [HaChooseAction.defaultConfig] }, { name: "Variables", actions: [{ variables: { hello: "1" } }] }, + { name: "Parallel", actions: [HaParallelAction.defaultConfig] }, ]; @customElement("demo-automation-editor-action") diff --git a/src/data/script.ts b/src/data/script.ts index a28369a289..dec65806c5 100644 --- a/src/data/script.ts +++ b/src/data/script.ts @@ -203,6 +203,10 @@ export interface StopAction extends BaseAction { error?: boolean; } +export interface ParallelAction extends BaseAction { + parallel: Action | Action[]; +} + interface UnknownAction extends BaseAction { [key: string]: unknown; } @@ -222,6 +226,7 @@ export type Action = | VariablesAction | PlayMediaAction | StopAction + | ParallelAction | UnknownAction; export interface ActionTypes { @@ -239,6 +244,7 @@ export interface ActionTypes { service: ServiceAction; play_media: PlayMediaAction; stop: StopAction; + parallel: ParallelAction; unknown: UnknownAction; } @@ -318,6 +324,9 @@ export const getActionType = (action: Action): ActionType => { if ("stop" in action) { return "stop"; } + if ("parallel" in action) { + return "parallel"; + } if ("service" in action) { if ("metadata" in action) { if (is(action, activateSceneActionStruct)) { diff --git a/src/data/script_i18n.ts b/src/data/script_i18n.ts index 230c867ef0..f6c1931cf9 100644 --- a/src/data/script_i18n.ts +++ b/src/data/script_i18n.ts @@ -169,5 +169,9 @@ export const describeAction = ( }`; } + if (actionType === "parallel") { + return "Run in parallel"; + } + return actionType; }; diff --git a/src/panels/config/automation/action/ha-automation-action-row.ts b/src/panels/config/automation/action/ha-automation-action-row.ts index 126468e545..119f22ca5c 100644 --- a/src/panels/config/automation/action/ha-automation-action-row.ts +++ b/src/panels/config/automation/action/ha-automation-action-row.ts @@ -33,6 +33,7 @@ import "./types/ha-automation-action-delay"; import "./types/ha-automation-action-device_id"; import "./types/ha-automation-action-event"; import "./types/ha-automation-action-if"; +import "./types/ha-automation-action-parallel"; import "./types/ha-automation-action-play_media"; import "./types/ha-automation-action-repeat"; import "./types/ha-automation-action-service"; @@ -54,6 +55,7 @@ const OPTIONS = [ "if", "device_id", "stop", + "parallel", ]; const getType = (action: Action | undefined) => { diff --git a/src/panels/config/automation/action/types/ha-automation-action-parallel.ts b/src/panels/config/automation/action/types/ha-automation-action-parallel.ts new file mode 100644 index 0000000000..0320bb2e26 --- /dev/null +++ b/src/panels/config/automation/action/types/ha-automation-action-parallel.ts @@ -0,0 +1,56 @@ +import { CSSResultGroup, html, LitElement } from "lit"; +import { customElement, property } from "lit/decorators"; +import { fireEvent } from "../../../../../common/dom/fire_event"; +import { Action, ParallelAction } from "../../../../../data/script"; +import { HaDeviceAction } from "./ha-automation-action-device_id"; +import { haStyle } from "../../../../../resources/styles"; +import type { HomeAssistant } from "../../../../../types"; +import "../ha-automation-action"; +import "../../../../../components/ha-textfield"; +import type { ActionElement } from "../ha-automation-action-row"; + +@customElement("ha-automation-action-parallel") +export class HaParallelAction extends LitElement implements ActionElement { + @property({ attribute: false }) public hass!: HomeAssistant; + + @property({ attribute: false }) public action!: ParallelAction; + + public static get defaultConfig() { + return { + parallel: [HaDeviceAction.defaultConfig], + }; + } + + protected render() { + const action = this.action; + + return html` + + `; + } + + private _actionsChanged(ev: CustomEvent) { + ev.stopPropagation(); + const value = ev.detail.value as Action[]; + fireEvent(this, "value-changed", { + value: { + ...this.action, + parallel: value, + }, + }); + } + + static get styles(): CSSResultGroup { + return haStyle; + } +} + +declare global { + interface HTMLElementTagNameMap { + "ha-automation-action-parallel": HaParallelAction; + } +} diff --git a/src/translations/en.json b/src/translations/en.json index 84f7b9f664..c84157181d 100755 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -2053,6 +2053,9 @@ "label": "Stop", "stop": "Reason for stopping", "error": "Stop because of an unexpected error" + }, + "parallel": { + "label": "Run in parallel" } } }