From 590bba0aca4fb84bd5b1c519c27c9cf966fe78ca Mon Sep 17 00:00:00 2001 From: c727 Date: Wed, 27 Jun 2018 03:45:40 +0200 Subject: [PATCH] Love: Card to show entites on picture (#1341) * Love: Card to show entites on picture * Lint * MVP + x * Feedback * Add toggle action * Lint --- .../lovelace/cards/hui-entity-filter-card.js | 2 - .../cards/hui-picture-elements-card.js | 140 ++++++++++++++++++ .../lovelace/common/create-card-element.js | 2 + 3 files changed, 142 insertions(+), 2 deletions(-) create mode 100644 src/panels/lovelace/cards/hui-picture-elements-card.js diff --git a/src/panels/lovelace/cards/hui-entity-filter-card.js b/src/panels/lovelace/cards/hui-entity-filter-card.js index 95509231bf..b0f1ee5926 100644 --- a/src/panels/lovelace/cards/hui-entity-filter-card.js +++ b/src/panels/lovelace/cards/hui-entity-filter-card.js @@ -1,7 +1,5 @@ import { PolymerElement } from '@polymer/polymer/polymer-element.js'; -import './hui-error-card'; - import computeStateDomain from '../../../common/entity/compute_state_domain.js'; import createCardElement from '../common/create-card-element'; diff --git a/src/panels/lovelace/cards/hui-picture-elements-card.js b/src/panels/lovelace/cards/hui-picture-elements-card.js new file mode 100644 index 0000000000..16b335c5a0 --- /dev/null +++ b/src/panels/lovelace/cards/hui-picture-elements-card.js @@ -0,0 +1,140 @@ +import { html } from '@polymer/polymer/lib/utils/html-tag.js'; +import { PolymerElement } from '@polymer/polymer/polymer-element.js'; + +import '../../../components/entity/state-badge.js'; +import '../../../components/ha-card.js'; + +import { STATES_ON } from '../../../common/const.js'; +import computeDomain from '../../../common/entity/compute_domain.js'; +import computeStateDisplay from '../../../common/entity/compute_state_display.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 + * @appliesMixin LocalizeMixin + */ +class HuiPictureElementsCard extends LocalizeMixin(EventsMixin(PolymerElement)) { + static get template() { + return html` + + + +
+
+`; + } + + static get properties() { + return { + hass: { + type: Object, + observer: '_hassChanged' + }, + config: { + type: Object, + observer: '_configChanged' + } + }; + } + + getCardSize() { + return 4; + } + + _configChanged(config) { + const root = this.$.root; + this._requiresStateObj = []; + + while (root.lastChild) { + root.removeChild(root.lastChild); + } + + if (config && config.image && config.elements) { + const img = document.createElement('img'); + img.src = config.image; + root.appendChild(img); + + config.elements.forEach((element) => { + let el; + if (element.type === 'state-badge') { + const entityId = element.entity; + const stateObj = this.hass.states[entityId]; + el = document.createElement('state-badge'); + el.stateObj = stateObj; + el.addEventListener('click', () => this._handleClick(entityId, element.action === 'toggle')); + el.classList.add('clickable'); + el.title = this._computeTooltip(stateObj); + if (element.style) { + Object.keys(element.style).forEach((prop) => { + el.style.setProperty(prop, element.style[prop]); + }); + } + this._requiresStateObj.push({ el, entityId }); + } + el.classList.add('entity'); + root.appendChild(el); + }); + } + } + + _hassChanged(hass) { + this._requiresStateObj.forEach((element) => { + const { el, entityId } = element; + const stateObj = hass.states[entityId]; + el.stateObj = stateObj; + el.title = this._computeTooltip(stateObj); + }); + } + + _computeTooltip(stateObj) { + return `${computeStateName(stateObj)}: ${computeStateDisplay(this.localize, stateObj)}`; + } + + _handleClick(entityId, toggle) { + if (toggle) { + const turnOn = !STATES_ON.includes(this.hass.states[entityId].state); + const stateDomain = computeDomain(entityId); + const serviceDomain = stateDomain === 'lock' || stateDomain === 'cover' ? + stateDomain : 'homeassistant'; + + let service; + switch (stateDomain) { + case 'lock': + service = turnOn ? 'unlock' : 'lock'; + break; + case 'cover': + service = turnOn ? 'open_cover' : 'close_cover'; + break; + default: + service = turnOn ? 'turn_on' : 'turn_off'; + } + this.hass.callService(serviceDomain, service, { entity_id: entityId }); + } else { + this.fire('hass-more-info', { entityId }); + } + } +} + +customElements.define('hui-picture-elements-card', HuiPictureElementsCard); diff --git a/src/panels/lovelace/common/create-card-element.js b/src/panels/lovelace/common/create-card-element.js index 65021f79dd..c2e57258a8 100644 --- a/src/panels/lovelace/common/create-card-element.js +++ b/src/panels/lovelace/common/create-card-element.js @@ -7,6 +7,7 @@ import '../cards/hui-iframe-card.js'; import '../cards/hui-markdown-card.js'; import '../cards/hui-media-control-card.js'; import '../cards/hui-entity-picture-card.js'; +import '../cards/hui-picture-elements-card'; import '../cards/hui-picture-glance-card'; import '../cards/hui-plant-status-card.js'; import '../cards/hui-weather-forecast-card'; @@ -22,6 +23,7 @@ const CARD_TYPES = [ 'iframe', 'markdown', 'media-control', + 'picture-elements', 'picture-glance', 'plant-status', 'weather-forecast'