diff --git a/gallery/src/pages/lovelace/tile-card.ts b/gallery/src/pages/lovelace/tile-card.ts index c5289165ea33..dc0743a81318 100644 --- a/gallery/src/pages/lovelace/tile-card.ts +++ b/gallery/src/pages/lovelace/tile-card.ts @@ -28,6 +28,9 @@ const ENTITIES = [ device_class: "lock", supported_features: LockEntityFeature.OPEN, }), + getEntity("media_player", "living_room", "playing", { + friendly_name: "Living room speaker", + }), getEntity("climate", "thermostat", "heat", { current_temperature: 73, min_temp: 45, @@ -197,6 +200,15 @@ const CONFIGS = [ - type: "lock-open-door" `, }, + { + heading: "Media player volume feature", + config: ` +- type: tile + entity: media_player.living_room + features: + - type: "media-player-volume" + `, + }, { heading: "Vacuum commands feature", config: ` diff --git a/src/panels/lovelace/card-features/hui-media-player-volume-card-feature.ts b/src/panels/lovelace/card-features/hui-media-player-volume-card-feature.ts new file mode 100644 index 000000000000..6f68e72cc0fd --- /dev/null +++ b/src/panels/lovelace/card-features/hui-media-player-volume-card-feature.ts @@ -0,0 +1,90 @@ +import type { HassEntity } from "home-assistant-js-websocket"; +import { html, LitElement, nothing } from "lit"; +import { customElement, property, state } from "lit/decorators"; +import { computeDomain } from "../../../common/entity/compute_domain"; +import { stateActive } from "../../../common/entity/state_active"; +import "../../../components/ha-control-slider"; +import { isUnavailableState } from "../../../data/entity"; +import type { HomeAssistant } from "../../../types"; +import type { LovelaceCardFeature } from "../types"; +import { cardFeatureStyles } from "./common/card-feature-styles"; +import type { MediaPlayerCardFeatureConfig } from "./types"; + +export const supportsMediaPlayerVolumeCardFeature = (stateObj: HassEntity) => { + const domain = computeDomain(stateObj.entity_id); + return domain === "media_player"; +}; + +@customElement("hui-media-player-volume-card-feature") +class HuiMediaPlayerVolumeCardFeature + extends LitElement + implements LovelaceCardFeature +{ + @property({ attribute: false }) public hass?: HomeAssistant; + + @property({ attribute: false }) public stateObj?: HassEntity; + + @state() private _config?: MediaPlayerCardFeatureConfig; + + static getStubConfig(): MediaPlayerCardFeatureConfig { + return { + type: "media-player-volume", + }; + } + + public setConfig(config: MediaPlayerCardFeatureConfig): void { + if (!config) { + throw new Error("Invalid configuration"); + } + this._config = config; + } + + protected render() { + if ( + !this._config || + !this.hass || + !this.stateObj || + !supportsMediaPlayerVolumeCardFeature(this.stateObj) + ) { + return nothing; + } + + const position = + this.stateObj.attributes.volume_level != null + ? Math.round(this.stateObj.attributes.volume_level * 100) + : undefined; + + return html` + + `; + } + + private _valueChanged(ev: CustomEvent) { + ev.stopPropagation(); + const value = ev.detail.value; + + this.hass!.callService("media_player", "volume_set", { + entity_id: this.stateObj!.entity_id, + volume_level: value / 100, + }); + } + + static get styles() { + return cardFeatureStyles; + } +} + +declare global { + interface HTMLElementTagNameMap { + "hui-media-player-volume-card-feature": HuiMediaPlayerVolumeCardFeature; + } +} diff --git a/src/panels/lovelace/card-features/types.ts b/src/panels/lovelace/card-features/types.ts index ec60914086f8..17251bc22c79 100644 --- a/src/panels/lovelace/card-features/types.ts +++ b/src/panels/lovelace/card-features/types.ts @@ -34,6 +34,10 @@ export interface LockOpenDoorCardFeatureConfig { type: "lock-open-door"; } +export interface MediaPlayerCardFeatureConfig { + type: "media-player-volume"; +} + export interface FanPresetModesCardFeatureConfig { type: "fan-preset-modes"; style?: "dropdown" | "icons"; @@ -161,6 +165,7 @@ export type LovelaceCardFeatureConfig = | LightColorTempCardFeatureConfig | LockCommandsCardFeatureConfig | LockOpenDoorCardFeatureConfig + | MediaPlayerCardFeatureConfig | NumericInputCardFeatureConfig | SelectOptionsCardFeatureConfig | TargetHumidityCardFeatureConfig diff --git a/src/panels/lovelace/create-element/create-card-feature-element.ts b/src/panels/lovelace/create-element/create-card-feature-element.ts index 872ceb0aba06..f8e3e49abdfa 100644 --- a/src/panels/lovelace/create-element/create-card-feature-element.ts +++ b/src/panels/lovelace/create-element/create-card-feature-element.ts @@ -17,6 +17,7 @@ import "../card-features/hui-light-brightness-card-feature"; import "../card-features/hui-light-color-temp-card-feature"; import "../card-features/hui-lock-commands-card-feature"; import "../card-features/hui-lock-open-door-card-feature"; +import "../card-features/hui-media-player-volume-card-feature"; import "../card-features/hui-numeric-input-card-feature"; import "../card-features/hui-select-options-card-feature"; import "../card-features/hui-target-temperature-card-feature"; @@ -51,6 +52,7 @@ const TYPES: Set = new Set([ "light-color-temp", "lock-commands", "lock-open-door", + "media-player-volume", "numeric-input", "select-options", "target-humidity", diff --git a/src/panels/lovelace/editor/config-elements/hui-card-features-editor.ts b/src/panels/lovelace/editor/config-elements/hui-card-features-editor.ts index 41564ebe5e57..01980ab7eb5e 100644 --- a/src/panels/lovelace/editor/config-elements/hui-card-features-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-card-features-editor.ts @@ -38,6 +38,7 @@ import { supportsLightBrightnessCardFeature } from "../../card-features/hui-ligh import { supportsLightColorTempCardFeature } from "../../card-features/hui-light-color-temp-card-feature"; import { supportsLockCommandsCardFeature } from "../../card-features/hui-lock-commands-card-feature"; import { supportsLockOpenDoorCardFeature } from "../../card-features/hui-lock-open-door-card-feature"; +import { supportsMediaPlayerVolumeCardFeature } from "../../card-features/hui-media-player-volume-card-feature"; import { supportsNumericInputCardFeature } from "../../card-features/hui-numeric-input-card-feature"; import { supportsSelectOptionsCardFeature } from "../../card-features/hui-select-options-card-feature"; import { supportsTargetHumidityCardFeature } from "../../card-features/hui-target-humidity-card-feature"; @@ -71,6 +72,7 @@ const UI_FEATURE_TYPES = [ "light-color-temp", "lock-commands", "lock-open-door", + "media-player-volume", "numeric-input", "select-options", "target-humidity", @@ -123,6 +125,7 @@ const SUPPORTS_FEATURE_TYPES: Record< "light-color-temp": supportsLightColorTempCardFeature, "lock-commands": supportsLockCommandsCardFeature, "lock-open-door": supportsLockOpenDoorCardFeature, + "media-player-volume": supportsMediaPlayerVolumeCardFeature, "numeric-input": supportsNumericInputCardFeature, "select-options": supportsSelectOptionsCardFeature, "target-humidity": supportsTargetHumidityCardFeature, diff --git a/src/translations/en.json b/src/translations/en.json index e8bfe80a397a..416e294c1849 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -6597,6 +6597,9 @@ "lock-open-door": { "label": "Lock open door" }, + "media-player-volume": { + "label": "Media player volume" + }, "vacuum-commands": { "label": "Vacuum commands", "commands": "Commands",