From 794808d3a70e2cc67b848328ce58646ef6e36cb2 Mon Sep 17 00:00:00 2001 From: Zack Arnett Date: Mon, 15 Oct 2018 14:07:13 -0400 Subject: [PATCH] Button Card - Lovelace Addition (#1766) * Initial Commit - Button Card * Fixing Coloring Review * Resolving Reviews * Updating last Reviews --- .../src/demos/demo-hui-entity-button-card.js | 95 +++++++++++ .../lovelace/cards/hui-entity-button-card.js | 161 ++++++++++++++++++ .../lovelace/common/create-card-element.js | 2 + 3 files changed, 258 insertions(+) create mode 100644 gallery/src/demos/demo-hui-entity-button-card.js create mode 100644 src/panels/lovelace/cards/hui-entity-button-card.js diff --git a/gallery/src/demos/demo-hui-entity-button-card.js b/gallery/src/demos/demo-hui-entity-button-card.js new file mode 100644 index 0000000000..439dd76e55 --- /dev/null +++ b/gallery/src/demos/demo-hui-entity-button-card.js @@ -0,0 +1,95 @@ +import { html } from "@polymer/polymer/lib/utils/html-tag.js"; +import { PolymerElement } from "@polymer/polymer/polymer-element.js"; + +import getEntity from "../data/entity.js"; +import provideHass from "../data/provide_hass.js"; +import "../components/demo-cards.js"; + +const ENTITIES = [ + getEntity("light", "bed_light", "on", { + friendly_name: "Bed Light", + }), +]; + +const CONFIGS = [ + { + heading: "Basic example", + config: ` +- type: entity-button + entity: light.bed_light + `, + }, + { + heading: "With Name", + config: ` +- type: entity-button + name: Bedroom + entity: light.bed_light + `, + }, + { + heading: "With Icon", + config: ` +- type: entity-button + entity: light.bed_light + icon: mdi:hotel + `, + }, + { + heading: "Without State", + config: ` +- type: entity-button + entity: light.bed_light + show_state: false + `, + }, + { + heading: "Custom Tap Action (toggle)", + config: ` +- type: entity-button + entity: light.bed_light + tap_action: toggle + `, + }, + { + heading: "Running Service", + config: ` +- type: entity-button + entity: light.bed_light + service: light.toggle + `, + }, + { + heading: "Invalid Entity", + config: ` +- type: entity-button + entity: sensor.invalid_entity + `, + }, +]; + +class DemoEntityButtonEntity extends PolymerElement { + static get template() { + return html` + + `; + } + + static get properties() { + return { + _configs: { + type: Object, + value: CONFIGS, + }, + hass: Object, + }; + } + + ready() { + super.ready(); + const hass = provideHass(this.$.demos); + hass.addEntities(ENTITIES); + } +} + +customElements.define("demo-hui-entity-button-card", DemoEntityButtonEntity); diff --git a/src/panels/lovelace/cards/hui-entity-button-card.js b/src/panels/lovelace/cards/hui-entity-button-card.js new file mode 100644 index 0000000000..b59d437cf3 --- /dev/null +++ b/src/panels/lovelace/cards/hui-entity-button-card.js @@ -0,0 +1,161 @@ +import { html } from "@polymer/polymer/lib/utils/html-tag.js"; +import { PolymerElement } from "@polymer/polymer/polymer-element.js"; +import { fireEvent } from "../../../common/dom/fire_event.js"; + +import "../../../components/ha-card.js"; + +import toggleEntity from "../common/entity/toggle-entity.js"; +import stateIcon from "../../../common/entity/state_icon.js"; +import computeStateDomain from "../../../common/entity/compute_state_domain.js"; +import computeStateName from "../../../common/entity/compute_state_name.js"; +import EventsMixin from "../../../mixins/events-mixin.js"; +import LocalizeMixin from "../../../mixins/localize-mixin.js"; + +/* + * @appliesMixin EventsMixin + */ +class HuiEntityButtonCard extends LocalizeMixin(EventsMixin(PolymerElement)) { + static get template() { + return html` + + + +
+ + [[_computeName(_stateObj)]] +
+
+
+ `; + } + + static get properties() { + return { + hass: { + type: Object, + }, + _config: Object, + _stateObj: { + type: Object, + computed: "_computeStateObj(hass.states, _config.entity)", + observer: "stateObjChanged", + }, + }; + } + + getCardSize() { + return 2; + } + + setConfig(config) { + if (!config || !config.entity) { + throw new Error("Invalid card configuration"); + } + this._config = { show_state: true, ...config }; + } + + _computeStateObj(states, entityId) { + return states && entityId in states ? states[entityId] : null; + } + + stateObjChanged() { + const stateObj = this._stateObj; + if (!stateObj) return; + + const iconStyle = { + color: "", + filter: "", + }; + if (stateObj.attributes.hs_color) { + const hue = stateObj.attributes.hs_color[0]; + const sat = stateObj.attributes.hs_color[1]; + if (sat > 10) iconStyle.color = `hsl(${hue}, 100%, ${100 - sat / 2}%)`; + } + if (stateObj.attributes.brightness) { + const brightness = stateObj.attributes.brightness; + iconStyle.filter = `brightness(${(brightness + 245) / 5}%)`; + } + Object.assign(this.$.ButtonIcon.style, iconStyle); + } + + _computeDomain(stateObj) { + if (!stateObj) return ""; + return computeStateDomain(stateObj); + } + + _computeName(stateObj) { + const config = this._config; + if (!stateObj) return "Entity not available: " + this._config.entity; + return config.name ? config.name : computeStateName(stateObj); + } + + _computeIcon(stateObj) { + const config = this._config; + if (!stateObj) return ""; + return config.icon ? config.icon : stateIcon(stateObj); + } + + _computeClassName(stateObj) { + if (!stateObj) return "not-found"; + return ""; + } + + _handleClick() { + if (!this._stateObj) return; + const config = this._config; + const stateObj = this._stateObj; + var entityId = stateObj.entity_id; + switch (config.tap_action) { + case "toggle": + toggleEntity(this.hass, entityId); + break; + case "call-service": { + const [domain, service] = config.service.split(".", 2); + const serviceData = { entity_id: entityId, ...config.service_data }; + this.hass.callService(domain, service, serviceData); + break; + } + default: + fireEvent(this, "hass-more-info", { entityId }); + } + } +} + +customElements.define("hui-entity-button-card", HuiEntityButtonCard); diff --git a/src/panels/lovelace/common/create-card-element.js b/src/panels/lovelace/common/create-card-element.js index 7422f9187b..354decfc9d 100644 --- a/src/panels/lovelace/common/create-card-element.js +++ b/src/panels/lovelace/common/create-card-element.js @@ -3,6 +3,7 @@ import { fireEvent } from "../../../common/dom/fire_event.js"; import "../cards/hui-alarm-panel-card.js"; import "../cards/hui-conditional-card.js"; import "../cards/hui-entities-card.js"; +import "../cards/hui-entity-button-card.js"; import "../cards/hui-entity-filter-card.js"; import "../cards/hui-error-card.js"; import "../cards/hui-glance-card.ts"; @@ -28,6 +29,7 @@ const CARD_TYPES = new Set([ "alarm-panel", "conditional", "entities", + "entity-button", "entity-filter", "error", "gauge",