diff --git a/src/components/ha-service-control.ts b/src/components/ha-service-control.ts
index 6be50e0191..8da1a98b4f 100644
--- a/src/components/ha-service-control.ts
+++ b/src/components/ha-service-control.ts
@@ -174,6 +174,7 @@ export class HaServiceControl extends LitElement {
if (this._value && serviceData) {
const loadDefaults = this.value && !("data" in this.value);
// Set mandatory bools without a default value to false
+ this._value = { ...this._value };
if (!this._value.data) {
this._value.data = {};
}
diff --git a/src/data/lovelace/config/action.ts b/src/data/lovelace/config/action.ts
index 800a54dc3f..04562c3e6d 100644
--- a/src/data/lovelace/config/action.ts
+++ b/src/data/lovelace/config/action.ts
@@ -1,4 +1,5 @@
import type { HassServiceTarget } from "home-assistant-js-websocket";
+import { Action } from "../../script";
export interface ToggleActionConfig extends BaseActionConfig {
action: "toggle";
@@ -31,6 +32,11 @@ export interface MoreInfoActionConfig extends BaseActionConfig {
entity_id?: string;
}
+export interface SequenceActionConfig extends BaseActionConfig {
+ action: "sequence";
+ actions?: Action[];
+}
+
export interface AssistActionConfig extends BaseActionConfig {
action: "assist";
pipeline_id?: string;
@@ -67,4 +73,5 @@ export type ActionConfig =
| MoreInfoActionConfig
| AssistActionConfig
| NoActionConfig
- | CustomActionConfig;
+ | CustomActionConfig
+ | SequenceActionConfig;
diff --git a/src/panels/lovelace/common/handle-action.ts b/src/panels/lovelace/common/handle-action.ts
index 3c51b0d468..16b7d57ff3 100644
--- a/src/panels/lovelace/common/handle-action.ts
+++ b/src/panels/lovelace/common/handle-action.ts
@@ -3,6 +3,7 @@ import { navigate } from "../../../common/navigate";
import { forwardHaptic } from "../../../data/haptics";
import { domainToName } from "../../../data/integration";
import { ActionConfig } from "../../../data/lovelace/config/action";
+import { callExecuteScript } from "../../../data/service";
import { showConfirmationDialog } from "../../../dialogs/generic/show-dialog-box";
import { showVoiceCommandDialog } from "../../../dialogs/voice-command-dialog/show-ha-voice-command-dialog";
import { HomeAssistant } from "../../../types";
@@ -177,6 +178,13 @@ export const handleAction = async (
});
break;
}
+ case "sequence": {
+ if (!actionConfig.actions) {
+ return;
+ }
+ callExecuteScript(hass, actionConfig.actions);
+ break;
+ }
case "fire-dom-event": {
fireEvent(node, "ll-custom", actionConfig);
}
diff --git a/src/panels/lovelace/components/hui-action-editor.ts b/src/panels/lovelace/components/hui-action-editor.ts
index dad65137ad..044a862e45 100644
--- a/src/panels/lovelace/components/hui-action-editor.ts
+++ b/src/panels/lovelace/components/hui-action-editor.ts
@@ -34,6 +34,7 @@ const DEFAULT_ACTIONS: UiAction[] = [
"navigate",
"url",
"perform-action",
+ "sequence",
"assist",
"none",
];
@@ -70,6 +71,15 @@ const ASSIST_SCHEMA = [
},
] as const satisfies readonly HaFormSchema[];
+const SEQUENCE_SCHEMA = [
+ {
+ name: "actions",
+ selector: {
+ action: {},
+ },
+ },
+] as const satisfies readonly HaFormSchema[];
+
@customElement("hui-action-editor")
export class HuiActionEditor extends LitElement {
@property({ attribute: false }) public config?: ActionConfig;
@@ -120,6 +130,10 @@ export class HuiActionEditor extends LitElement {
}
}
+ protected firstUpdated(_changedProperties: PropertyValues): void {
+ this.hass!.loadFragmentTranslation("config");
+ }
+
protected render() {
if (!this.hass) {
return nothing;
@@ -218,6 +232,17 @@ export class HuiActionEditor extends LitElement {
`
: nothing}
+ ${this.config?.action === "sequence"
+ ? html`
+
+ `
+ : nothing}
`;
}
@@ -289,7 +314,15 @@ export class HuiActionEditor extends LitElement {
});
}
- private _computeFormLabel(schema: SchemaUnion) {
+ private _computeFormLabel(
+ schema:
+ | SchemaUnion
+ | SchemaUnion
+ | SchemaUnion
+ ) {
+ if (schema.name === "actions") {
+ return "";
+ }
return this.hass?.localize(
`ui.panel.lovelace.editor.action-editor.${schema.name}`
);
diff --git a/src/panels/lovelace/editor/structs/action-struct.ts b/src/panels/lovelace/editor/structs/action-struct.ts
index d1f8d90c48..12632cc852 100644
--- a/src/panels/lovelace/editor/structs/action-struct.ts
+++ b/src/panels/lovelace/editor/structs/action-struct.ts
@@ -48,6 +48,12 @@ const actionConfigStructService = object({
confirmation: optional(actionConfigStructConfirmation),
});
+const actionConfigStructSequence = object({
+ action: literal("sequence"),
+ actions: optional(array(object())),
+ confirmation: optional(actionConfigStructConfirmation),
+});
+
const actionConfigStructNavigate = object({
action: literal("navigate"),
navigation_path: string(),
@@ -101,6 +107,9 @@ export const actionConfigStruct = dynamic((value) => {
case "more-info": {
return actionConfigStructMoreInfo;
}
+ case "sequence": {
+ return actionConfigStructSequence;
+ }
}
}
diff --git a/src/translations/en.json b/src/translations/en.json
index 029a4cffc8..e0df4d17d9 100644
--- a/src/translations/en.json
+++ b/src/translations/en.json
@@ -5752,10 +5752,12 @@
"more-info": "More info",
"toggle": "Toggle",
"navigate": "Navigate",
+ "sequence": "Sequence",
"assist": "Assist",
"url": "URL",
"none": "Nothing"
- }
+ },
+ "sequence_actions": "Actions"
},
"condition-editor": {
"explanation": "The card will be shown when ALL conditions below are fulfilled.",