diff --git a/src/data/lovelace.ts b/src/data/lovelace.ts
index 090bb0dfc0..447b803dec 100644
--- a/src/data/lovelace.ts
+++ b/src/data/lovelace.ts
@@ -2,6 +2,7 @@ import {
Connection,
getCollection,
HassEventBase,
+ HassServiceTarget,
} from "home-assistant-js-websocket";
import { HASSDomEvent } from "../common/dom/fire_event";
import { HuiErrorCard } from "../panels/lovelace/cards/hui-error-card";
@@ -120,8 +121,8 @@ export interface ToggleActionConfig extends BaseActionConfig {
export interface CallServiceActionConfig extends BaseActionConfig {
action: "call-service";
service: string;
+ target?: HassServiceTarget;
service_data?: {
- entity_id?: string | [string];
[key: string]: any;
};
}
diff --git a/src/panels/lovelace/common/handle-action.ts b/src/panels/lovelace/common/handle-action.ts
index ad95273e5d..a4339e2fe4 100644
--- a/src/panels/lovelace/common/handle-action.ts
+++ b/src/panels/lovelace/common/handle-action.ts
@@ -130,7 +130,12 @@ export const handleAction = async (
return;
}
const [domain, service] = actionConfig.service.split(".", 2);
- hass.callService(domain, service, actionConfig.service_data);
+ hass.callService(
+ domain,
+ service,
+ actionConfig.service_data,
+ actionConfig.target
+ );
forwardHaptic("light");
break;
}
diff --git a/src/panels/lovelace/components/hui-action-editor.ts b/src/panels/lovelace/components/hui-action-editor.ts
index 7946138d6e..831c493735 100644
--- a/src/panels/lovelace/components/hui-action-editor.ts
+++ b/src/panels/lovelace/components/hui-action-editor.ts
@@ -15,15 +15,17 @@ import {
} from "lit-element";
import { fireEvent } from "../../../common/dom/fire_event";
import "../../../components/ha-help-tooltip";
-import "../../../components/ha-service-picker";
import {
ActionConfig,
CallServiceActionConfig,
NavigateActionConfig,
UrlActionConfig,
} from "../../../data/lovelace";
+import { ServiceAction } from "../../../data/script";
import { HomeAssistant } from "../../../types";
import { EditorTarget } from "../editor/types";
+import "../../../components/ha-service-control";
+import memoizeOne from "memoize-one";
@customElement("hui-action-editor")
export class HuiActionEditor extends LitElement {
@@ -47,10 +49,15 @@ export class HuiActionEditor extends LitElement {
return config.url_path || "";
}
- get _service(): string {
- const config = this.config as CallServiceActionConfig;
- return config.service || "";
- }
+ private _serviceAction = memoizeOne(
+ (config: CallServiceActionConfig): ServiceAction => {
+ return {
+ service: config.service || "",
+ data: config.service_data,
+ target: config.target,
+ };
+ }
+ );
protected render(): TemplateResult {
if (!this.hass || !this.actions) {
@@ -117,17 +124,13 @@ export class HuiActionEditor extends LitElement {
: ""}
${this.config?.action === "call-service"
? html`
-
-
- ${this.hass!.localize(
- "ui.panel.lovelace.editor.action-editor.editor_service_data"
- )}
-
+ .value=${this._serviceAction(this.config)}
+ .showAdvanced=${this.hass.userData?.showAdvanced}
+ narrow
+ @value-changed=${this._serviceValueChanged}
+ >
`
: ""}
`;
@@ -174,6 +177,18 @@ export class HuiActionEditor extends LitElement {
}
}
+ private _serviceValueChanged(ev: CustomEvent) {
+ ev.stopPropagation();
+ fireEvent(this, "value-changed", {
+ value: {
+ ...this.config!,
+ service: ev.detail.value.service || "",
+ service_data: ev.detail.value.data || {},
+ target: ev.detail.value.target || {},
+ },
+ });
+ }
+
static get styles(): CSSResult {
return css`
.dropdown {
diff --git a/src/panels/lovelace/editor/types.ts b/src/panels/lovelace/editor/types.ts
index 2cd040cf37..c37c3e084d 100644
--- a/src/panels/lovelace/editor/types.ts
+++ b/src/panels/lovelace/editor/types.ts
@@ -120,20 +120,27 @@ const actionConfigStructConfirmation = union([
const actionConfigStructUrl = object({
action: literal("url"),
- url_path: string(),
+ url_path: optional(string()),
confirmation: optional(actionConfigStructConfirmation),
});
const actionConfigStructService = object({
action: literal("call-service"),
- service: string(),
+ service: optional(string()),
service_data: optional(object()),
+ target: optional(
+ object({
+ entity_id: optional(union([string(), array(string())])),
+ device_id: optional(union([string(), array(string())])),
+ area_id: optional(union([string(), array(string())])),
+ })
+ ),
confirmation: optional(actionConfigStructConfirmation),
});
const actionConfigStructNavigate = object({
action: literal("navigate"),
- navigation_path: string(),
+ navigation_path: optional(string()),
confirmation: optional(actionConfigStructConfirmation),
});