diff --git a/src/data/entity_attributes.ts b/src/data/entity_attributes.ts index ce914ecc98..ad80f4365d 100644 --- a/src/data/entity_attributes.ts +++ b/src/data/entity_attributes.ts @@ -23,6 +23,7 @@ export const STATE_ATTRIBUTES = [ "state_class", "supported_features", "unit_of_measurement", + "available_tones", ]; export const TEMPERATURE_ATTRIBUTES = new Set([ diff --git a/src/data/siren.ts b/src/data/siren.ts new file mode 100644 index 0000000000..7da521fa9c --- /dev/null +++ b/src/data/siren.ts @@ -0,0 +1,7 @@ +export const SirenEntityFeature = { + TURN_ON: 1, + TURN_OFF: 2, + TONES: 4, + VOLUME_SET: 8, + DURATION: 16, +}; diff --git a/src/dialogs/more-info/components/siren/ha-more-info-siren-advanced-controls.ts b/src/dialogs/more-info/components/siren/ha-more-info-siren-advanced-controls.ts new file mode 100644 index 0000000000..93fa0df503 --- /dev/null +++ b/src/dialogs/more-info/components/siren/ha-more-info-siren-advanced-controls.ts @@ -0,0 +1,224 @@ +import type { CSSResultGroup } from "lit"; +import { css, html, LitElement, nothing } from "lit"; +import { customElement, property, query, state } from "lit/decorators"; +import type { HassEntity } from "home-assistant-js-websocket"; +import { mdiClose, mdiPlay, mdiStop } from "@mdi/js"; +import type { HomeAssistant } from "../../../../types"; +import { stopPropagation } from "../../../../common/dom/stop_propagation"; +import { + getMobileCloseToBottomAnimation, + getMobileOpenFromBottomAnimation, +} from "../../../../components/ha-md-dialog"; +import "../../../../components/ha-dialog-header"; +import "../../../../components/ha-icon-button"; +import "../../../../components/ha-button"; +import "../../../../components/ha-textfield"; +import "../../../../components/ha-control-button"; +import "../../../../components/ha-select"; +import "../../../../components/ha-list-item"; +import type { HaMdDialog } from "../../../../components/ha-md-dialog"; +import { fireEvent } from "../../../../common/dom/fire_event"; +import { supportsFeature } from "../../../../common/entity/supports-feature"; +import { SirenEntityFeature } from "../../../../data/siren"; +import { haStyle } from "../../../../resources/styles"; + +@customElement("ha-more-info-siren-advanced-controls") +class MoreInfoSirenAdvancedControls extends LitElement { + @property({ attribute: false }) public hass!: HomeAssistant; + + @state() _stateObj?: HassEntity; + + @state() _tone?: string; + + @state() _volume?: number; + + @state() _duration?: number; + + @query("ha-md-dialog") private _dialog?: HaMdDialog; + + public showDialog({ stateObj }: { stateObj: HassEntity }) { + this._stateObj = stateObj; + } + + public closeDialog(): void { + this._dialog?.close(); + } + + private _dialogClosed(): void { + this._stateObj = undefined; + fireEvent(this, "dialog-closed", { dialog: this.localName }); + } + + render() { + if (!this._stateObj) { + return nothing; + } + const supportsTones = + supportsFeature(this._stateObj, SirenEntityFeature.TONES) && + this._stateObj.attributes.available_tones; + const supportsVolume = supportsFeature( + this._stateObj, + SirenEntityFeature.VOLUME_SET + ); + const supportsDuration = supportsFeature( + this._stateObj, + SirenEntityFeature.DURATION + ); + return html` + + + + ${this.hass.localize( + "ui.components.siren.advanced_controls" + )} + +
+
+ ${supportsTones + ? html` + + ${Object.entries( + this._stateObj.attributes.available_tones + ).map( + ([toneId, toneName]) => html` + ${toneName} + ` + )} + + ` + : nothing} + ${supportsVolume + ? html` + + ` + : nothing} + ${supportsDuration + ? html` + + ` + : nothing} +
+
+ + + + + + +
+
+
+ + ${this.hass.localize("ui.common.close")} + +
+
+ `; + } + + private _handleToneChange(ev) { + this._tone = ev.target.value; + } + + private _handleVolumeChange(ev) { + this._volume = parseFloat(ev.target.value) / 100; + if (isNaN(this._volume)) { + this._volume = undefined; + } + } + + private _handleDurationChange(ev) { + this._duration = parseInt(ev.target.value); + if (isNaN(this._duration)) { + this._duration = undefined; + } + } + + private async _turnOn() { + await this.hass.callService("siren", "turn_on", { + entity_id: this._stateObj!.entity_id, + tone: this._tone, + volume: this._volume, + duration: this._duration, + }); + } + + private async _turnOff() { + await this.hass.callService("siren", "turn_off", { + entity_id: this._stateObj!.entity_id, + }); + } + + static get styles(): CSSResultGroup { + return [ + haStyle, + css` + .options { + display: flex; + flex-direction: column; + gap: 16px; + } + .controls { + display: flex; + flex-direction: row; + justify-content: center; + gap: 16px; + margin-top: 16px; + } + ha-control-button { + --control-button-border-radius: 16px; + --mdc-icon-size: 24px; + width: 64px; + height: 64px; + } + `, + ]; + } +} + +declare global { + interface HTMLElementTagNameMap { + "ha-more-info-siren-advanced-controls": MoreInfoSirenAdvancedControls; + } +} diff --git a/src/dialogs/more-info/components/siren/show-dialog-siren-advanced-controls.ts b/src/dialogs/more-info/components/siren/show-dialog-siren-advanced-controls.ts new file mode 100644 index 0000000000..4913ebd012 --- /dev/null +++ b/src/dialogs/more-info/components/siren/show-dialog-siren-advanced-controls.ts @@ -0,0 +1,18 @@ +import type { HassEntity } from "home-assistant-js-websocket"; +import { fireEvent } from "../../../../common/dom/fire_event"; + +export const loadSirenAdvancedControlsView = () => + import("./ha-more-info-siren-advanced-controls"); + +export const showSirenAdvancedControlsView = ( + element: HTMLElement, + stateObj: HassEntity +): void => { + fireEvent(element, "show-dialog", { + dialogTag: "ha-more-info-siren-advanced-controls", + dialogImport: loadSirenAdvancedControlsView, + dialogParams: { + stateObj, + }, + }); +}; diff --git a/src/dialogs/more-info/controls/more-info-siren.ts b/src/dialogs/more-info/controls/more-info-siren.ts index c7b8e1a552..191427e611 100644 --- a/src/dialogs/more-info/controls/more-info-siren.ts +++ b/src/dialogs/more-info/controls/more-info-siren.ts @@ -5,9 +5,13 @@ import { LitElement, html, nothing } from "lit"; import { customElement, property } from "lit/decorators"; import "../../../components/ha-attributes"; import "../../../state-control/ha-state-control-toggle"; +import "../../../components/ha-button"; import type { HomeAssistant } from "../../../types"; import "../components/ha-more-info-state-header"; import { moreInfoControlStyle } from "../components/more-info-control-style"; +import { supportsFeature } from "../../../common/entity/supports-feature"; +import { SirenEntityFeature } from "../../../data/siren"; +import { showSirenAdvancedControlsView } from "../components/siren/show-dialog-siren-advanced-controls"; @customElement("more-info-siren") class MoreInfoSiren extends LitElement { @@ -20,6 +24,20 @@ class MoreInfoSiren extends LitElement { return nothing; } + const supportsTones = + supportsFeature(this.stateObj, SirenEntityFeature.TONES) && + this.stateObj.attributes.available_tones; + const supportsVolume = supportsFeature( + this.stateObj, + SirenEntityFeature.VOLUME_SET + ); + const supportsDuration = supportsFeature( + this.stateObj, + SirenEntityFeature.DURATION + ); + // show advanced controls dialog if extra features are supported + const allowAdvanced = supportsTones || supportsVolume || supportsDuration; + return html` + ${allowAdvanced + ? html` + ${this.hass.localize("ui.components.siren.advanced_controls")} + ` + : nothing}