diff --git a/src/data/alarm_control_panel.ts b/src/data/alarm_control_panel.ts new file mode 100644 index 0000000000..58f33c601d --- /dev/null +++ b/src/data/alarm_control_panel.ts @@ -0,0 +1,18 @@ +import { HomeAssistant } from "../types"; + +export const callAlarmAction = ( + hass: HomeAssistant, + entity: string, + action: + | "arm_away" + | "arm_home" + | "arm_night" + | "arm_custom_bypass" + | "disarm", + code: string +) => { + hass!.callService("alarm_control_panel", "alarm_" + action, { + entity_id: entity, + code, + }); +}; diff --git a/src/panels/lovelace/cards/hui-alarm-panel-card.js b/src/panels/lovelace/cards/hui-alarm-panel-card.js deleted file mode 100644 index 6c7b9679c8..0000000000 --- a/src/panels/lovelace/cards/hui-alarm-panel-card.js +++ /dev/null @@ -1,273 +0,0 @@ -import { html } from "@polymer/polymer/lib/utils/html-tag"; -import { PolymerElement } from "@polymer/polymer/polymer-element"; - -import "../../../components/ha-card"; - -import EventsMixin from "../../../mixins/events-mixin"; -import LocalizeMixin from "../../../mixins/localize-mixin"; -import "../../../components/ha-label-badge"; - -/* - * @appliesMixin EventsMixin - */ - -const Icons = { - armed_away: "hass:security-lock", - armed_custom_bypass: "hass:security", - armed_home: "hass:security-home", - armed_night: "hass:security-home", - disarmed: "hass:verified", - pending: "hass:shield-outline", - triggered: "hass:bell-ring", -}; - -export const Config = { - name: "", - entity: "", - states: "", -}; - -class HuiAlarmPanelCard extends LocalizeMixin(EventsMixin(PolymerElement)) { - static async getConfigElement() { - await import("../editor/config-elements/hui-alarm-panel-card-editor"); - return document.createElement("hui-alarm-panel-card-editor"); - } - - static getStubConfig() { - return { states: ["arm_home", "arm_away"] }; - } - - static get template() { - return html` - - - - - - `; - } - - static get properties() { - return { - hass: { - type: Object, - }, - _config: Object, - _stateObj: { - type: Object, - computed: "_computeStateObj(hass.states, _config.entity)", - }, - _value: { - type: String, - value: "", - }, - }; - } - - getCardSize() { - return 4; - } - - setConfig(config) { - if ( - !config || - !config.entity || - config.entity.split(".")[0] !== "alarm_control_panel" - ) { - throw new Error("Invalid card configuration"); - } - - const defaults = { - states: ["arm_away", "arm_home"], - }; - - this._config = { ...defaults, ...config }; - this._icons = Icons; - } - - _computeStateObj(states, entityId) { - return states && entityId in states ? states[entityId] : null; - } - - _computeHeader(localize, stateObj) { - if (!stateObj) return ""; - return this._config.name - ? this._config.name - : this._label(localize, stateObj.state); - } - - _computeIcon(stateObj) { - return this._icons[stateObj.state] || "hass:shield-outline"; - } - - _label(localize, state) { - return ( - localize(`state.alarm_control_panel.${state}`) || - localize(`ui.card.alarm_control_panel.${state}`) - ); - } - - _stateIconLabel(state) { - const stateLabel = state.split("_").pop(); - return stateLabel === "disarmed" || stateLabel === "triggered" - ? "" - : stateLabel; - } - - _showActionToggle(state) { - return state === "disarmed"; - } - - _computeClassName(stateObj) { - if (!stateObj) return "not-found"; - return ""; - } - - _handlePadClick(e) { - const val = e.target.getAttribute("value"); - this._value = val === "clear" ? "" : this._value + val; - } - - _handleActionClick(e) { - this.hass.callService("alarm_control_panel", "alarm_" + e.target.id, { - entity_id: this._stateObj.entity_id, - code: this._value, - }); - this._value = ""; - } -} - -customElements.define("hui-alarm-panel-card", HuiAlarmPanelCard); diff --git a/src/panels/lovelace/cards/hui-alarm-panel-card.ts b/src/panels/lovelace/cards/hui-alarm-panel-card.ts new file mode 100644 index 0000000000..ae83f1b7ca --- /dev/null +++ b/src/panels/lovelace/cards/hui-alarm-panel-card.ts @@ -0,0 +1,302 @@ +import { + html, + LitElement, + PropertyValues, + PropertyDeclarations, +} from "@polymer/lit-element"; +import { TemplateResult } from "lit-html"; +import { classMap } from "lit-html/directives/classMap"; + +import { LovelaceCard } from "../types"; +import { HomeAssistant } from "../../../types"; +import { LovelaceCardConfig } from "../../../data/lovelace"; +import { callAlarmAction } from "../../../data/alarm_control_panel"; +import { hassLocalizeLitMixin } from "../../../mixins/lit-localize-mixin"; + +import "../../../components/ha-card"; +import "../../../components/ha-label-badge"; +import { + createErrorCardConfig, + createErrorCardElement, +} from "./hui-error-card"; + +const ICONS = { + armed_away: "hass:security-lock", + armed_custom_bypass: "hass:security", + armed_home: "hass:security-home", + armed_night: "hass:security-home", + disarmed: "hass:verified", + pending: "hass:shield-outline", + triggered: "hass:bell-ring", +}; + +const BUTTONS = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "", "0", "clear"]; + +export interface Config extends LovelaceCardConfig { + entity: string; + name?: string; + states?: string[]; +} + +class HuiAlarmPanelCard extends hassLocalizeLitMixin(LitElement) + implements LovelaceCard { + public static async getConfigElement() { + await import("../editor/config-elements/hui-alarm-panel-card-editor"); + return document.createElement("hui-alarm-panel-card-editor"); + } + + public static getStubConfig() { + return { states: ["arm_home", "arm_away"] }; + } + + public hass?: HomeAssistant; + private _config?: Config; + private _code?: string; + + static get properties(): PropertyDeclarations { + return { + hass: {}, + _config: {}, + _code: {}, + }; + } + + public getCardSize(): number { + return 4; + } + + public setConfig(config: Config): void { + if ( + !config || + !config.entity || + config.entity.split(".")[0] !== "alarm_control_panel" + ) { + throw new Error("Invalid card configuration"); + } + + const defaults = { + states: ["arm_away", "arm_home"], + }; + + this._config = { ...defaults, ...config }; + this._code = ""; + } + + protected shouldUpdate(changedProps: PropertyValues): boolean { + if (changedProps.has("_config") || changedProps.has("_code")) { + return true; + } + + const oldHass = changedProps.get("hass") as HomeAssistant | undefined; + if (oldHass) { + return ( + oldHass.states[this._config!.entity] !== + this.hass!.states[this._config!.entity] + ); + } + return true; + } + + protected render(): TemplateResult { + if (!this._config || !this.hass) { + return html``; + } + const stateObj = this.hass.states[this._config.entity]; + + if (!stateObj) { + const element = createErrorCardElement( + createErrorCardConfig("Entity not Found!", this._config) + ); + return html` + ${element} + `; + } + + return html` + ${this.renderStyle()} + + +
+ ${ + (stateObj.state === "disarmed" + ? this._config.states! + : ["disarm"] + ).map((state) => { + return html` + ${this._label(state)} + `; + }) + } +
+ +
+ ${ + BUTTONS.map((value) => { + return value === "" + ? html` + + ` + : html` + ${ + value === "clear" ? this._label("clear_code") : value + } + `; + }) + } +
+
+ `; + } + + private _stateIconLabel(state: string): string { + const stateLabel = state.split("_").pop(); + return stateLabel === "disarmed" || + stateLabel === "triggered" || + !stateLabel + ? "" + : stateLabel; + } + + private _label(state: string): string { + return ( + this.localize(`state.alarm_control_panel.${state}`) || + this.localize(`ui.card.alarm_control_panel.${state}`) + ); + } + + private _handlePadClick(e: MouseEvent): void { + const val = (e.currentTarget! as any).value; + this._code = val === "clear" ? "" : this._code + val; + } + + private _handleActionClick(e: MouseEvent): void { + callAlarmAction( + this.hass!, + this._config!.entity_id, + (e.currentTarget! as any).action, + this._code! + ); + this._code = ""; + } + + private renderStyle(): TemplateResult { + return html` + + `; + } +} + +declare global { + interface HTMLElementTagNameMap { + "hui-alarm-panel-card": HuiAlarmPanelCard; + } +} + +customElements.define("hui-alarm-panel-card", HuiAlarmPanelCard);