diff --git a/src/dialogs/more-info/controls/more-info-light.ts b/src/dialogs/more-info/controls/more-info-light.ts
index 30b3fa1d4f..9d81cfdc01 100644
--- a/src/dialogs/more-info/controls/more-info-light.ts
+++ b/src/dialogs/more-info/controls/more-info-light.ts
@@ -3,8 +3,8 @@ import {
mdiBrightness6,
mdiCreation,
mdiFileWordBox,
- mdiLightbulb,
mdiLightbulbOff,
+ mdiLightbulbOn,
mdiPower,
} from "@mdi/js";
import type { CSSResultGroup, PropertyValues } from "lit";
@@ -12,8 +12,8 @@ import { LitElement, css, html, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import { stopPropagation } from "../../../common/dom/stop_propagation";
import { supportsFeature } from "../../../common/entity/supports-feature";
-import "../../../components/ha-attributes";
import "../../../components/ha-attribute-icon";
+import "../../../components/ha-attributes";
import "../../../components/ha-control-select-menu";
import "../../../components/ha-icon-button-group";
import "../../../components/ha-icon-button-toggle";
@@ -121,7 +121,7 @@ class MoreInfoLight extends LitElement {
`
diff --git a/src/panels/lovelace/card-features/common/card-feature-styles.ts b/src/panels/lovelace/card-features/common/card-feature-styles.ts
index 6a0fdcb1c0..5787f1d1d2 100644
--- a/src/panels/lovelace/card-features/common/card-feature-styles.ts
+++ b/src/panels/lovelace/card-features/common/card-feature-styles.ts
@@ -27,4 +27,12 @@ export const cardFeatureStyles = css`
--control-slider-thickness: var(--feature-height);
--control-slider-border-radius: var(--feature-border-radius);
}
+ ha-control-switch {
+ --control-switch-on-color: var(--feature-color);
+ --control-switch-off-color: var(--feature-color);
+ --control-switch-background-opacity: 0.2;
+ --control-switch-thickness: var(--feature-height);
+ --control-switch-border-radius: var(--feature-border-radius);
+ --control-switch-padding: 0px;
+ }
`;
diff --git a/src/panels/lovelace/card-features/hui-toggle-card-feature.ts b/src/panels/lovelace/card-features/hui-toggle-card-feature.ts
index bf233f5a9a..96cfce4161 100644
--- a/src/panels/lovelace/card-features/hui-toggle-card-feature.ts
+++ b/src/panels/lovelace/card-features/hui-toggle-card-feature.ts
@@ -1,23 +1,50 @@
-import { mdiPowerOff, mdiPower } from "@mdi/js";
+import {
+ mdiFan,
+ mdiFanOff,
+ mdiLightbulbOff,
+ mdiLightbulbOn,
+ mdiPower,
+ mdiPowerOff,
+ mdiVolumeHigh,
+ mdiVolumeOff,
+} from "@mdi/js";
import type { HassEntity } from "home-assistant-js-websocket";
-import type { TemplateResult } from "lit";
-import { LitElement, html } from "lit";
+import { LitElement, css, html, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
+import { classMap } from "lit/directives/class-map";
import { styleMap } from "lit/directives/style-map";
import { computeDomain } from "../../../common/entity/compute_domain";
import { stateColorCss } from "../../../common/entity/state_color";
-import "../../../components/ha-control-select";
-import type { ControlSelectOption } from "../../../components/ha-control-select";
-import { UNAVAILABLE } from "../../../data/entity";
+import "../../../components/ha-control-button";
+import "../../../components/ha-control-button-group";
+import "../../../components/ha-control-switch";
+import { UNAVAILABLE, UNKNOWN } from "../../../data/entity";
+import { forwardHaptic } from "../../../data/haptics";
import type { HomeAssistant } from "../../../types";
import type { LovelaceCardFeature } from "../types";
import { cardFeatureStyles } from "./common/card-feature-styles";
import type { ToggleCardFeatureConfig } from "./types";
-import { showToast } from "../../../util/toast";
export const supportsToggleCardFeature = (stateObj: HassEntity) => {
const domain = computeDomain(stateObj.entity_id);
- return ["switch", "input_boolean"].includes(domain);
+ return ["switch", "input_boolean", "light", "fan", "siren", "valve"].includes(
+ domain
+ );
+};
+
+const DOMAIN_ICONS: Record = {
+ siren: {
+ on: mdiVolumeHigh,
+ off: mdiVolumeOff,
+ },
+ light: {
+ on: mdiLightbulbOn,
+ off: mdiLightbulbOff,
+ },
+ fan: {
+ on: mdiFan,
+ off: mdiFanOff,
+ },
};
@customElement("hui-toggle-card-feature")
@@ -41,67 +68,120 @@ class HuiToggleCardFeature extends LitElement implements LovelaceCardFeature {
this._config = config;
}
- protected render(): TemplateResult | null {
+ private _valueChanged(ev) {
+ const checked = ev.target.checked as boolean;
+
+ if (checked) {
+ this._turnOn();
+ } else {
+ this._turnOff();
+ }
+ }
+
+ private _turnOn() {
+ this._callService(true);
+ }
+
+ private _turnOff() {
+ this._callService(false);
+ }
+
+ private async _callService(turnOn): Promise {
+ if (!this.hass || !this.stateObj) {
+ return;
+ }
+ forwardHaptic("light");
+ const stateDomain = computeDomain(this.stateObj.entity_id);
+ const serviceDomain = stateDomain;
+ const service = turnOn ? "turn_on" : "turn_off";
+
+ await this.hass.callService(serviceDomain, service, {
+ entity_id: this.stateObj.entity_id,
+ });
+ }
+
+ protected render() {
if (
!this._config ||
!this.hass ||
!this.stateObj ||
!supportsToggleCardFeature(this.stateObj)
) {
- return null;
+ return nothing;
}
- const color = stateColorCss(this.stateObj);
+ const onColor = "var(--feature-color)";
+ const offColor = stateColorCss(this.stateObj, "off");
- const options = ["off", "on"].map((entityState) => ({
- value: entityState,
- label: this.hass!.formatEntityState(this.stateObj!, entityState),
- path: entityState === "on" ? mdiPower : mdiPowerOff,
- }));
+ const isOn = this.stateObj.state === "on";
+ const isOff = this.stateObj.state === "off";
+
+ const domain = computeDomain(this.stateObj.entity_id);
+ const onIcon = DOMAIN_ICONS[domain]?.on || mdiPower;
+ const offIcon = DOMAIN_ICONS[domain]?.off || mdiPowerOff;
+
+ if (
+ this.stateObj.attributes.assumed_state ||
+ this.stateObj.state === UNKNOWN
+ ) {
+ return html`
+
+
+
+
+
+
+
+
+ `;
+ }
return html`
-
-
+
`;
}
- private async _valueChanged(ev: CustomEvent) {
- const newState = (ev.detail as any).value;
-
- if (
- newState === this.stateObj!.state &&
- !this.stateObj!.attributes.assumed_state
- )
- return;
- const service = newState === "on" ? "turn_on" : "turn_off";
- const domain = computeDomain(this.stateObj!.entity_id);
-
- try {
- await this.hass!.callService(domain, service, {
- entity_id: this.stateObj!.entity_id,
- });
- } catch (_err) {
- showToast(this, {
- message: this.hass!.localize("ui.notification_toast.action_failed", {
- service: domain + "." + service,
- }),
- duration: 5000,
- dismissable: true,
- });
- }
+ static get styles() {
+ return [
+ cardFeatureStyles,
+ css`
+ ha-control-button.active {
+ --control-button-icon-color: white;
+ --control-button-background-color: var(--color);
+ --control-button-background-opacity: 1;
+ }
+ `,
+ ];
}
-
- static styles = cardFeatureStyles;
}
declare global {